Palisade Errors
Security-conscious error handling for high-assurance Rust applications.
Palisade Errors is designed for systems where information leakage is a security vulnerability. Built as the foundational error handling layer for the Palisade Honeypot System, it enforces a strict separation between "what happened" (forensics) and "what the adversary sees" (sanitization), while guaranteeing that sensitive data in memory is zeroized immediately after use.
Current Version: 1.0.1
π― Design Philosophy
In a honeypot, every error is intelligence:
- For attackers: Errors reveal system architecture, validation logic, and attack surface.
- For defenders: Errors provide forensic trails, attack correlation, and threat intelligence.
Palisade Errors ensures attackers see only walls, while defenders see everything.
ποΈ Architecture
The library is built around two complementary error models that share the same security philosophy:
AgentError β The Operational Layer
The primary error type for day-to-day use. Wraps a subsystem error code, operation context, optional sensitive source, metadata tags, and a retryability flag. All construction automatically applies session-specific error code obfuscation and enforces a 1 Β΅s constant-time floor to prevent timing side-channels.
DualContextError β The Deception Layer
A newer, type-enforced dual-context model built for honeypot-specific scenarios. It holds two explicitly typed contexts that cannot be confused at compile time:
PublicContextβ what the adversary sees. Either aLie(always available) or aTruth(gated behind theexternal_signalingfeature flag).InternalContextβ what SOC analysts see. Can beDiagnostic,Sensitive, or a trackedLie(for log exfiltration scenarios).
Neither type implements Display in a leaking way. InternalContext::Display always emits [INTERNAL CONTEXT REDACTED]. You access internal content via explicit methods with deliberate API surface.
SocAccess β Capability-Based Sensitive Access
Accessing Sensitive-classified internal context requires a SocAccess capability token:
let access = acquire;
if let Some = context.expose_sensitive
This is not cryptographic. Its purpose is organizational safety: making sensitive data access grep-able, explicit, and impossible to call accidentally through a generic formatting path.
Attacker Request
β
Application Logic (fails)
β
βββββββββββββββββββββββββββββββββββββββββββ
β AgentError / DualContextError β
β β
β ββββββββββββββββββββββββββββββββββββββ β
β β External (Display / PublicContext) β ββββ Sanitized/deceptive response
β β "Configuration failed (E-CFG-103)" β β (zero information leakage)
β ββββββββββββββββββββββββββββββββββββββ β
β β
β ββββββββββββββββββββββββββββββββββββββ β
β β Internal (InternalLog / Internal β ββββ SOC forensic logs
β β Context) β Full diagnostic context β β (complete audit trail)
β ββββββββββββββββββββββββββββββββββββββ β
β β
β ββββββββββββββββββββββββββββββββββββββ β
β β Sensitive (ZeroizeOnDrop + β ββββ Encrypted, access-controlled
β β volatile writes) β PII, creds, β β restricted-access storage
β β paths, keys β β (requires SocAccess token)
β ββββββββββββββββββββββββββββββββββββββ β
βββββββββββββββββββββββββββββββββββββββββββ
β (on drop)
Best-effort Memory Zeroization
π Key Features
- Forensic Integrity: Full stack traces, variable values, and internal state are preserved for your logs β but never reach the adversary.
- Dual-Context Model:
DualContextErrorgives type-enforced separation of public lies from internal truth. - Capability-Based Access:
SocAccessprevents accidental sensitive data exposure through generic formatting paths. - Information Hiding:
Displayon all error types is sanitized to reveal only error codes and categories. - Memory Safety: Sensitive data lives in
ZeroizeOnDropwrappers. Owned strings receive volatile writes on drop to defeat LLVM dead-store elimination. Secrets are wiped from memory as soon as the error is dropped. - Always-On Obfuscation: Session salts are applied at construction time. The same semantic error produces different codes across sessions, defeating fingerprinting.
- DoS Protection: Log outputs are strictly truncated. Convenience macros enforce
sanitized!()wrapping for dynamic arguments. - Strict Taxonomy: Feature flags enforce rigid error categorization at compile time.
- Timing Attack Mitigation: Built-in 1 Β΅s constant-time floor at construction, plus
with_timing_normalization()for sensitive operation windows. - Bounded Forensic Logging:
RingBufferLoggerprovides fixed-memory, DoS-proof forensic log storage.
βοΈ Feature Flags
| Flag | Default | Effect |
|---|---|---|
strict_taxonomy |
Off | Enforces namespaceβcategory mappings at compile time. Must be enabled in CI. |
strict_severity |
Off | Restricts Breach-level impacts to namespaces with can_breach authority. Recommended for production. |
external_signaling |
Off | Enables PublicContext::truth() and DualContextError::with_truth(). Without this flag, all external output must be deceptive β enforced at compile time. |
trusted_debug |
Off | Enables InternalLog::format_for_trusted_debug(). Only activates in debug_assertions builds. |
tokio / async_std |
Off | Enables AgentError::with_timing_normalization_async() for non-blocking timing normalization. |
π Usage
Basic AgentError
use ;
Adversary sees:
Configuration operation failed [permanent] (E-CFG-107)
// Note: code is session-obfuscated β not E-CFG-104
Your logs contain:
[E-CFG-107] operation='check_access' details="User 'attacker' denied"
Sensitive Data with AgentError
use ;
let err = config_sensitive;
The Dual-Context Model
For maximum deception control, use DualContextError directly:
use ;
// Adversary sees generic error. SOC sees SQL injection attempt.
let err = with_lie;
// External category is also masked: Detection β "Routine Operation"
assert_eq!;
When even internal logs might be exfiltrated:
let err = with_double_lie;
Sensitive internal data:
let err = with_lie_and_sensitive;
// Normal logging β no sensitive data emitted
if let Some = err.internal.payload
// Restricted access β requires SocAccess capability
let access = acquire;
if let Some = err.internal.expose_sensitive
When external_signaling is enabled, you may emit truthful external messages for benign errors that improve the honeypot's authenticity:
// Only compiles with feature = "external_signaling"
let err = with_truth;
Without the feature flag, PublicContext::truth() and DualContextError::with_truth() do not exist β compile-time enforcement of the deception-only policy.
Building Errors with ContextBuilder
For complex error construction with a fluent API:
use ;
let err = new
.public_lie
.internal_diagnostic
.category
.build;
Secure Logging with AgentError
if let Err = result
Convenience Macros
Macros enforce compile-time safety: operation names and format strings must be string literals, and dynamic arguments must be wrapped in sanitized!():
use ;
let line_num = 42;
// β Correct β literal format, sanitized dynamic argument
let err = config_err!;
// β Compile error β operation must be a literal, not a runtime string
let err = config_err!;
sanitized!() truncates to 256 characters at UTF-8 boundaries and replaces control characters with ? to prevent log injection.
Attack Correlation with AgentError
let err = config_sensitive
.with_metadata
.with_metadata
.with_metadata;
correlator.track_error;
Timing Attack Mitigation
use ;
use Duration;
Both paths take at least 100 ms, preventing user enumeration via response time. For async runtimes, use with_timing_normalization_async() (requires tokio or async_std feature).
Bounded Forensic Logging
use RingBufferLogger;
use ;
// Max 1000 entries, 2 KB per entry = 2 MB total memory ceiling
let logger = new;
let err = config;
logger.log;
let recent = logger.get_recent;
for entry in recent
Oldest entries are evicted FIFO. Concurrent reads are supported via RwLock. No unbounded growth regardless of attack volume.
Error Code Obfuscation
Obfuscation is applied automatically at AgentError construction. You can also use it directly:
use obfuscation;
// Per-session setup (call once per connection/session)
let salt = generate_random_salt;
init_session_salt;
// Session 1: E-CFG-103, Session 2: E-CFG-106, Session 3: E-CFG-101
// Attacker cannot correlate codes across sessions.
βοΈ Governance & Taxonomy
Strict governance of error codes and namespaces is critical to preventing information leakage through taxonomy drift.
π See ERROR_GOVERNANCE.md for the complete taxonomy rules, authority models, and feature flag requirements.
β‘ Performance
This crate is architected for zero-leak memory management and microsecond-level predictability, even on legacy hardware.
π See BENCH_AVG.md for detailed benchmarks, timing normalization analysis, and hardware validation.
π License
Licensed under Apache-2.0.