Security Features
Security Features and Protections
Write Protection
Super Simple Includes implements strict write protection to prevent accidental or malicious writes to critical system directories.
Protected System Directories (MUST BLOCK)
The following directories are strictly protected. Any attempt to write to these locations will result in an error:
/bin- System binaries/dev- Device files/etc- System configuration/lib- System libraries/lib64- 64-bit system libraries/proc- Process information/root- Root user home/sbin- System administration binaries/usr- User programs and data
Allowed Directories (NO WARNING)
Writes to the following directories are considered normal and will not generate warnings:
/home- User home directories/var- Variable data (logs, temporary files, etc.)/opt- Optional/third-party software/mnt- Temporary mount points/run/media- Removable media mount points
Unusual Locations (WARNING)
Writes to any location not listed above will generate a warning but will be allowed to proceed. This includes:
/tmp- Temporary files (warning because deployments here are unusual)- Custom mount points
- Other non-standard locations
Symlink Protection
All symlinks are resolved to their real paths before checking. This prevents bypass attempts such as:
- Creating a symlink to
/etcand trying to write through it - Using complex symlink chains to obscure the final destination
- Directory traversal attacks using
../sequences
Path Resolution
Before any write operation:
- The path is normalized to remove
.and..components - Symlinks are resolved to their real destinations
- The final resolved path is checked against the protection rules
Implementation Requirements
Both the Rust implementation MUST:
- Block writes to protected system directories with a clear error message
- Warn about writes to unusual locations (outside allowed directories)
- Resolve symlinks to prevent bypass attempts
- Normalize paths to prevent traversal attacks
- Apply these checks to all write operations (deployments, preserve operations, etc.)
Error Messages
When blocking a write, the error message should:
- Clearly indicate that the operation was blocked for security reasons
- Specify which protected directory was targeted
- Suggest using an allowed directory instead
Example:
Error: Cannot write to protected system directory /etc
Please choose a deployment directory under /home, /var, /opt, /mnt, or /run/media
Testing
Security tests are located in tests/security/write_protection.py and verify:
- Direct writes to system directories are blocked
- Symlink bypasses are prevented
- Directory traversal attacks are blocked
- Warnings are generated for unusual locations
- Allowed directories work without warnings
- Complex symlink chains are properly resolved
Source Path Validation
Super Simple Includes enforces strict validation on all source paths in configuration files to ensure they remain within the site directory.
Path Restrictions
All source paths in ssi-config.toml must be relative paths within the site directory. The following are strictly forbidden:
- Absolute paths - Paths starting with
/ - Parent directory references - Paths containing
..
This applies to:
- Processing steps (
[[step]]) - Allsourcepaths - Include sources (
[[step]]) - Allsourcepaths
Security Rationale
These restrictions prevent:
- Information disclosure - Accessing sensitive files outside the site directory
- Path traversal attacks - Using
../sequences to escape the site boundary - Configuration confusion - Unclear dependencies on external files
Examples
β Forbidden Configurations
# Absolute path - NOT ALLOWED
[[step]]
emoji = "π"
source = "/etc/passwd" # β Absolute path
processing = "preserve"
# Parent directory reference - NOT ALLOWED
[[step]]
emoji = "π"
path = "../config/environment.txt" # β Parent directory reference
type = "environment"
# Multiple parent references - NOT ALLOWED
[[step]]
emoji = "π"
source = "../../shared/pages/" # β Escapes site directory
processing = "page"
β Correct Configurations
# Relative path within site - ALLOWED
[[step]]
emoji = "π"
path = "preservelist.txt" # β
Relative to site directory
processing = "preserve"
# Subdirectory path - ALLOWED
[[step]]
emoji = "π"
source = "config/environment.txt" # β
Within site directory
type = "environment"
# Nested subdirectories - ALLOWED
[[step]]
emoji = "π"
path = "content/pages/" # β
Stays within site
processing = "page"
Error Messages
When a forbidden path is detected:
β Absolute paths not allowed in Processing steps configuration: '/etc/passwd'
π‘ All source paths must be relative to the site directory
β Parent directory references not allowed in Include sources paths: '../secret.txt'
π‘ All source paths must be within the site directory
Symlink Security
In addition to the path restrictions above, source paths that are symlinks are validated to ensure they donβt escape the site directory:
- Direct symlinks - If a source path is a symlink, it must point to a location within the site directory
- Symlink chains - Symlinks that point to other symlinks are followed to their final destination, which must be within the site directory
- No escape allowed - Even if the symlink itself is within the site directory, if it points outside, it will be rejected
Examples of Forbidden Symlinks
# In site directory:
ln -s /etc/passwd evil-symlink
ln -s ../../../secrets/api-keys external-link
ln -s external-link chained-link
# All of these would be rejected:
[[step]]
source = "evil-symlink" # β Points to /etc/passwd
source = "external-link" # β Points outside site
source = "chained-link" # β Eventually points outside
Note on Preserve Lists and Environment Files
While the paths TO these configuration files must be within the site directory, the CONTENTS of preserve lists are separately validated with even stricter rules (see preserve processor documentation for details).
Unicode Security Protections
Super Simple Includes implements protection against Unicode-based attacks, including bidirectional text injection and other Unicode exploitation vectors.
Bidirectional Text Injection Protection
SSI blocks all nine dangerous bidirectional (bidi) control characters that can create visual spoofing attacks:
- U+202A (LRE - Left-to-Right Embedding)
- U+202B (RLE - Right-to-Left Embedding)
- U+202C (PDF - Pop Directional Formatting)
- U+202D (LRO - Left-to-Right Override)
- U+202E (RLO - Right-to-Left Override)
- U+2066 (LRI - Left-to-Right Isolate)
- U+2067 (RLI - Right-to-Left Isolate)
- U+2068 (FSI - First Strong Isolate)
- U+2069 (PDI - Pop Directional Isolate)
Multi-Layer Defense Strategy
Protection occurs at three validation points:
- Token Name Validation (Config Parsing): Rejects bidi controls in emoji prefixes and TOML keys at configuration load time
- File Content Validation (Filesystem Read): Validates template content inline as files are read
- Final Output Validation (Pre-Write): Safety gate validation just before writing to disk
This defense-in-depth approach ensures that even if bidi characters are introduced through complex token substitution, they will be caught before deployment.
Legitimate RTL Text
Important: These protections do not affect legitimate right-to-left languages!
β Allowed: Arabic, Hebrew, and other RTL text work naturally without needing bidi control characters:
Ω
Ψ±ΨΨ¨Ψ§ (Arabic)
Χ©ΧΧΧ (Hebrew)
β Blocked: Text with embedded bidi control characters:
text\u202e (Text with RLO)
RTL languages display correctly without explicit bidi control characters in token names or simple content.
Error Messages
When SSI detects a bidi control character, it provides detailed information:
π¨ Security: file content in index.html contains bidirectional control character
Text: "token\u202ename"
Character: '\u202e' (U+202E)
π‘ Bidi controls can create visual spoofing attacks
π§ Remove bidirectional control characters from your content
Documentation
For more information about Unicode security threats and SSIβs protections:
- See
docs/help/unicode-security-overview.mdfor user guide - See test suite in
tests/security/test_*.pyfor validation behavior
Implementation
Both the Rust implementation provide identical Unicode security protections using character iteration (not regex) for reliable detection across all platforms.