Create me an AuditLogger class whose constructor takes a sanitized String log message, where construction with malicious input (file path traversal, terminal escape sequences) leaves the logger in a 'rejected' state.
← Security and Sanitization · Ref: Q1246
The 'sanitized' modifier works on constructor parameters identically to function and method parameters. When a class is constructed with malicious input, the constructor sees an UNSET parameter, allowing the object to set itself into a safe default state rather than throwing an exception.
CLASS WITH SANITIZED CONSTRUCTOR PARAMETER
AuditLogger
message as String: "<no message>"
state as String: "empty"
AuditLogger()
-> incomingMessage as sanitized String
if incomingMessage? message: incomingMessage state: "clean" else state: "rejected"
getMessage()
<- rtn as String: message
getState()
<- rtn as String: state
default operator ?
The field defaults ensure the object is always well-formed. The constructor body branches on 'incomingMessage?' to record whether the input was accepted.
DEMONSTRATING ACCEPTED AND REJECTED INPUTS
This example varies the payload types — file path traversal, ANSI terminal escape codes (which the runtime reports as LOG_INJECTION), and a bare embedded newline — rather than the usual SQL/XSS strings, to show that 'sanitized' applies to ANY untrusted input, not just web payloads. It also shows what is NOT rejected: a plain newline inside the text is not treated as a threat, so the logger reports 'clean' for it:
// Clean log message log1 <- AuditLogger("User alice logged in successfully") // "clean"
// Path traversal attempt log2 <- AuditLogger("file=../../../etc/shadow") // "rejected"
// ANSI escape attempt (reported as LOG_INJECTION) log3 <- AuditLogger("Login\u001b[31m FAILED \u001b[0m") // "rejected"
// A bare embedded newline is NOT flagged log4 <- AuditLogger("action=lookup
2025-01-01 ADMIN_OVERRIDE")
// "clean"
Each rejection also writes a JSON warning line to stderr naming the threat (PATH_TRAVERSAL, LOG_INJECTION). If your log format is line-oriented, split or escape newlines yourself: 'sanitized' does not do it for you.
KEY ADVANTAGE
The object remains usable even when the input was malicious — it just records 'rejected' instead of 'clean'. The caller can inspect getState() to know the outcome. No exceptions, no try/catch, no nullable result wrapping.
See Q1237 for sanitized function parameters. See Q1247 for sanitized method parameters. See Q272 for defense in depth.
Example
#!ek9 defines module qa.security.auditloggerconstructor defines class AuditLogger message as String: "<no message>" state as String: "empty" AuditLogger() -> incomingMessage as sanitized String if incomingMessage? message: incomingMessage state: "clean" else state: "rejected" getMessage() <- rtn as String: message getState() <- rtn as String: state default operator ? defines program SanitizedAuditLoggerDemo() stdout <- Stdout() stdout.println("=== AuditLogger Sanitization Demo ===") cleanMessage <- "User alice logged in successfully" log1 <- AuditLogger(cleanMessage) stdout.println("Clean: " + log1.getState()) pathTraversal <- "file=../../../etc/shadow" log2 <- AuditLogger(pathTraversal) stdout.println("Path: " + log2.getState()) ansiEscape <- "Login\u001b[31m FAILED \u001b[0m" log3 <- AuditLogger(ansiEscape) stdout.println("ANSI: " + log3.getState()) logInjection <- "action=lookup\n2025-01-01 ADMIN_OVERRIDE" log4 <- AuditLogger(logInjection) stdout.println("Inject: " + log4.getState()) stdout.println("=== Complete ===")
Common mistakes
E07910 — The sanitized modifier can only be applied to String parameters. Injection attacks travel as text, so a non-String type has nothing to clean. See ek9 -h E07910 for details.
Incorrect:
-> incomingMessage as sanitized Integer
Correct:
-> incomingMessage as sanitized String
Other ways to ask this
- Show me how the sanitized keyword works on a constructor parameter for an audit logger.
- Write a logging class that rejects malicious log messages at construction time.
- Implement an AuditLogger that validates its incoming message via the sanitized modifier.
- Build an object that records whether its construction message was clean or rejected.
Coming from another language?
Java: validation in setters with throw on invalid input, or Optional<AuditLogger> wrapper. Kotlin: data class with init { require(...) } that throws. Rust: TryFrom<String> for AuditLogger with Result return type. Python: __init__ raises ValueError. EK9: 'sanitized' modifier on the constructor parameter — input is unset if rejected, object always constructs successfully with a state field indicating which path was taken.
Keywords: ANSI escape, AuditLogger, audit, constructor, input validation, log injection, path traversal, sanitized