Security Layer Reference
⚠ HERITAGE EXTRACTION — donor AMS security layer (Wave 8 quarantine)
This file extracts the donor AMS security layer from
src/security/andsrc/middleware/auth*.js(all deleted R53). The injection-detection regexes, the auth/ACL middleware, and theauth-permissions.jsladder are donor accretion. Phase 0 Colibri ships a 5-stage α middleware chain (tool-lock → schema-validate → audit-enter → dispatch → audit-exit) with no JWT, no API keys, no ACL, no rate limiter. Schema validation in Phase 0 is Zod-based at the dispatch boundary, not regex injection scanning. Authentication, authorization, and rate-limiting are Phase 1+ territory (see../../security/auth.mdheritage banner).Read this file as donor genealogy only.
The AMS security layer has two sub-layers: (1) src/security/ — static analysis utilities (injection detection, sanitization, validation), and (2) src/middleware/auth.js + src/middleware/acl.js — runtime authentication and authorization. For full auth/ACL documentation see middleware-chain-extraction.md.
src/security/audit.js — Threat Detection
detectSqlInjection(input) → {detected, confidence, patterns[], input}
Tests input against 12 regex patterns plus SQL keyword heuristics.
- Confidence:
0.2per regex match +0.1per SQL keyword, capped at1.0 - Keywords checked:
SELECT, INSERT, UPDATE, DELETE, DROP, UNION, EXEC, EXECUTE - Returns:
{ detected: boolean, confidence: number (0–1), patterns: string[], input: string (truncated at 100) }
Pattern categories covered:
- Classic:
%27,',--,# - UNION-based:
UNION SELECT - Tautology:
' OR '1'='1 - Stacked queries:
'; DROP TABLE - Execution:
exec sp_* - DDL:
INSERT INTO,DELETE FROM,DROP TABLE,ALTER TABLE
detectPathTraversal(input) → {detected, confidence, patterns[]}
Tests against 10 patterns:
../,..\,%2e%2e%2f,%2e%2e\,..\/%2f,%252e%252e%252f,\..\\,\\..\\- Returns same shape as
detectSqlInjection.
detectCommandInjection(input) → {detected, confidence, patterns[]}
Patterns:
- Shell metacharacters:
; cmd,& cmd,| cmd,` cmd` - Subshell:
$(cmd),`cmd` - Common payloads:
; rm,; cat,; echo
scanForSecrets(content, options?) → {found, secrets[]}
Scans text for exposed credentials. Excludes matches containing: example, test, fake, mock, dummy (configurable via options.excludePatterns).
Detected secret types:
| Type | Severity | Pattern |
|——|———-|———|
| api_key | critical | *api_key* = "XXXXXXXX" |
| secret_key | critical | *secret_key* = "XXXXXXXX" |
| private_key | critical | -----BEGIN * PRIVATE KEY----- |
| password | high | password = "XXXXXXXX" |
| token | high | *token* = "XXXXXXXXXXXXXXXX" |
| aws_key | critical | AKIAXXXXXXXXXXXXXXXX |
| github_token | critical | ghp_/gho_/ghu_/ghs_/ghr_* |
| slack_token | critical | xoxb-*/xoxa-* |
src/security/sanitizer.js — Input Sanitization
escapeHtml(input) → string
Replaces & < > " ' / with HTML entities.
stripDangerousChars(input) → string
Removes < > & " ' / \ characters.
sanitizeForSql(input) → string
Escapes for use in SQL string contexts (use only when parameterized queries not possible):
- Removes null bytes
- Doubles single quotes:
'→'' - Escapes backslashes:
\→\\
sanitizePath(path, options?) → {success, value, error?}
- Detects path traversal via
detectPathTraversal() - Normalizes path separators (
\→/) - Removes null bytes and control characters (
\x00–\x1F,\x7F–\x9F) - Validates allowed characters:
/^[a-zA-Z0-9_\-\.\/]+$/ - Options:
{ basePath, allowedChars }Returns{ success: false, error: "..." }on violations.
sanitizeJson(input, options?) → {success, value, error?}
Parses and re-serializes JSON, with optional max-depth and allowed-key filtering.
sanitizeObject(obj, schema?) → object
Recursively sanitizes object values via schema-defined rules.
src/security/validator.js — Input Validation Framework
Built on Zod. Used throughout domain handlers.
ValidationError
class ValidationError extends Error {
name = "ValidationError"
code = "VALIDATION_ERROR"
details: ZodIssue[]
}
SecurityError
class SecurityError extends Error {
name = "SecurityError"
code = "SECURITY_VIOLATION"
threatType: string
confidence: number
}
sanitizedString(options) → ZodSchema
Creates a string schema with optional: min, max, pattern, email, url, trim, nonempty.
Does NOT automatically run security scans — those must be added via .refine().
validateId(id, options?) → {valid, value?, error?, security?}
Validates ID strings:
- Type check: must be
string - Length: default max 100 chars
- Pattern: default
/^[a-zA-Z0-9_-]+$/ - Path traversal check: fails if
confidence > 0.5
validateFilePath(filePath, options?) → {valid, value?, error?, details?}
- Calls
detectPathTraversal() - Null byte check
- Extension whitelist/blacklist: default blocked =
.exe .bat .cmd .sh .dll .so - Options:
{ allowedExtensions[], blockedExtensions[] }
validateJson(content, options?) → {valid, value?, error?}
Parses JSON string. Returns { valid: true, value: parsedObject } or error.
Authentication Summary (src/middleware/auth.js)
JWT-based, algorithm: HS256, library: jose.
Auth modes (controlled by AMS_AUTH_MODE):
trust(default): no auth requiredtoken: validate if token presenthybrid: prefer token, accept unauthenticatedrequired: reject all requests without valid token
Token claims:
{
"sub": "userId",
"iss": "ams-server",
"aud": "ams-mcp-tools",
"iat": 1234567890,
"exp": 1234571490,
"jti": "tok-<32-hex-chars>",
"ams": {
"role": "admin",
"perms": ["task:create", "roadmap:write"],
"scope": "project:my-project",
"session": "session-uuid",
"name": "My Token"
}
}
Secret management priority: env var → secret file → auto-generate to ~/.ams/auth-secret (mode 0600).
Revocation: in-memory Map, 7-day TTL per entry, interval cleanup.
ACL Summary (src/middleware/acl.js)
Project-scoped RBAC. Graceful degradation: when AMS_USER_ID not set, all tools pass through.
Role levels: owner=4 > admin=3 > member=2 > viewer=1
Enforcement flow:
- Check
AMS_ACL_ENABLED(=!!AMS_USER_ID) - Look up
TOOL_PERMISSIONS[toolName]— defaults to'member'for unknown tools null= tool requires no project context → return early- Resolve project via
resolveProjectContext()(4-step cascade) - Lookup user role via
dbGetUserRole(projectId, userId) - Compare
ROLE_HIERARCHY[userRole] >= ROLE_HIERARCHY[requiredRole]
Error messages:
"ACL: Tool 'X' requires a project context. Set AMS_CURRENT_PROJECT env var, use unified_set_project, or pass project_id parameter.""ACL: Access denied for 'X'. Requires Y role, user has Z"
Token Permission Map Summary (src/middleware/auth-permissions.js)
Parallel permission system for token-based auth (complementary to ACL roles).
Permission format: resource:action[:scope] with wildcard *.
Resource categories and typical permissions:
| Resource | Read | Write | Admin |
|———-|——|——-|——-|
| roadmap | roadmap:list, roadmap:get, roadmap:read | roadmap:write, roadmap:register | roadmap:admin, roadmap:export |
| task | task:list, task:read | task:create, task:update, task:delete, task:write | — |
| audit | audit:read | audit:write | — |
| thought | thought:read | thought:write | — |
| merkle | merkle:read | merkle:write | — |
| memory | memory:read | memory:write | memory:admin |
| rag | rag:read | rag:write | rag:admin |
| gsd | gsd:read | gsd:write | gsd:admin |
| context | context:read | context:write | — |
| analysis | analysis:read | — | analysis:admin |
Wildcard *:* grants all permissions (superadmin).