Enforces security rules (SEC-1 through SEC-7). Loaded by the conductor for security audits, PR/code reviews, incident response, and new service scaffolding. Detects hardcoded secrets, insecure credential handling, XSS vectors, SQL injection, gitignore gaps, stale credentials, and CORS misconfigurations. Invokes scripts/scan_secrets.sh for automated scanning. Activated by: "security audit", "check for secrets", "vulnerabilities", "hardcoded key", "SQL injection", "review".
From clean-code-codexnpx claudepluginhub mikecubed/agent-orchestration --plugin clean-code-codexThis skill uses the workspace's default tool permissions.
Guides Next.js Cache Components and Partial Prerendering (PPR) with cacheComponents enabled. Implements 'use cache', cacheLife(), cacheTag(), revalidateTag(), static/dynamic optimization, and cache debugging.
Migrates code, prompts, and API calls from Claude Sonnet 4.0/4.5 or Opus 4.1 to Opus 4.5, updating model strings on Anthropic, AWS, GCP, Azure platforms.
Details PluginEval's skill quality evaluation: 3 layers (static, LLM judge), 10 dimensions, rubrics, formulas, anti-patterns, badges. Use to interpret scores, improve triggering, calibrate thresholds.
Precedence: SEC- (BLOCK)* → TDD → ARCH/TYPE → all quality checks.
Hook coverage check (run first):
Before invoking scan_secrets.sh, check whether the hook already reported
findings for this session:
cat "$COVERAGE_FILE" 2>/dev/null # COVERAGE_FILE = /tmp/codex-hook-coverage-<PROJECT_HASH>.jsonl
For each JSON line where "rule" is "SEC-1" or "SEC-7", extract file and line.
When subsequently scanning with scan_secrets.sh, skip any finding where the
file+rule+line triple matches an existing coverage record.
Log: "Skipping {rule} at {file}:{line} — already reported by hook this session."
If no coverage file exists, proceed normally with the full scan.
For automated scanning: invoke scripts/scan_secrets.sh --path {scope}
(and --history if the --history flag was passed) and parse its output
before performing manual pattern checks. Requires Python 3.12+.
Severity: BLOCK | Languages: * | Source: CCC
What it prohibits: Secrets of any kind stored in source code, including:
Detection:
scripts/scan_secrets.sh --path {scope} (+ --history if requested)findings array[A-Za-z0-9+/]{32,} in assignment context (=, :)password, secret, api_key, token, private_key
assigned to non-empty string literals-----BEGIN in source filesagent_action:
SEC-1 (BLOCK): Hardcoded secret detected at {file}:{line} — pattern: '{pattern}'.process.env.MY_SECRET, os.environ["MY_SECRET"], etc.
c. Add the variable name to a .env.example file (value: your-value-here)
d. Add .env to .gitignore--history flag was used and secret is in git history: cite SEC-1 and advise git history rewrite (git filter-repo or BFG). Require explicit confirmation before executing.--fix: replace the literal value with the env var reference (do NOT delete the literal from the report — it must be rotated)Bypass prohibition: "It's just a test key", "It's in a private repo", "It's a local dev secret" → Refuse. Cite SEC-1. No secret is safe in source control.
Severity: BLOCK | Languages: * | Source: CCC
What it prohibits: Reading sensitive configuration values (secrets, URLs containing credentials, private keys) without validating them at startup. An application that starts with a missing or malformed secret will fail in production, not in development where it is easiest to fix.
Required pattern:
// TypeScript
const config = z.object({ MY_SECRET: z.string().min(1) }).parse(process.env);
# Python
from pydantic_settings import BaseSettings
class Settings(BaseSettings): my_secret: str
Detection:
process.env.*, os.environ, os.Getenv, std::env::var readssecret, password, key,
token, cert) is validated through a schema (Zod, Pydantic, Viper, etc.)agent_action:
SEC-2 (BLOCK): Unvalidated env var access for '{var_name}' at {file}:{line}.--fix: add the schema validation wrapper at the top of the config moduleSeverity: BLOCK | Languages: typescript, javascript | Source: CCC
What it prohibits:
dangerouslySetInnerHTML={{ __html: userInput }} (React)innerHTML = userInputdocument.write(userInput)eval(userInput) or eval(dynamicString)new Function(userInput)setTimeout(userInput, ...) or setInterval(userInput, ...) with string argumentExemptions:
dangerouslySetInnerHTML={{ __html: sanitize(input) }} where sanitize is
DOMPurify or an equivalent library — document the library choiceeval in test infrastructure only (e.g., jest transform)Detection:
dangerouslySetInnerHTML, innerHTML, document.write in non-test fileseval( in non-test source filesnew Function( in non-test source filesagent_action:
SEC-3 (BLOCK): XSS injection vector at {file}:{line} — '{pattern}'.eval with a safer dispatch pattern (e.g., a lookup table)--fix: replace the injection point with the safe alternativeSeverity: BLOCK | Languages: * | Source: CCC
What it prohibits: Building SQL queries by concatenating or interpolating user-supplied strings. This is the most common class of SQL injection vulnerability and has zero legitimate use cases.
Prohibited patterns:
// TypeScript
db.query("SELECT * FROM users WHERE id = " + userId)
db.query(`SELECT * FROM users WHERE id = ${userId}`)
# Python
cursor.execute("SELECT * FROM users WHERE id = " + user_id)
cursor.execute(f"SELECT * FROM users WHERE id = {user_id}")
Required patterns:
// TypeScript
db.query("SELECT * FROM users WHERE id = $1", [userId])
# Python
cursor.execute("SELECT * FROM users WHERE id = %s", (user_id,))
Detection:
SELECT, INSERT, UPDATE, DELETE,
WHERE, FROM) inside string concatenation (+ operator or template literals
containing variable expressions) or f-stringsagent_action:
SEC-4 (BLOCK): SQL injection vulnerability at {file}:{line}. Raw string interpolation in SQL query.$1, %s, ?, @p1)--fix: rewrite as parameterised querySeverity: WARN | Languages: * | Source: CCC
What it checks: The .gitignore at the repository root contains entries for
common sensitive file patterns. Missing entries are a latent SEC-1 risk.
Required entries (at minimum):
.env
.env.*
!.env.example
*.pem
*.key
*.p12
*.pfx
*.jks
secrets/
config/secrets.yaml
Detection:
.gitignore at repo root (and any subdirectory .gitignore within scope)agent_action:
SEC-5 (WARN): .gitignore missing pattern '{pattern}' — sensitive files may be accidentally committed.--fix: add missing patterns to .gitignoregit status to check if any currently-tracked files match the new patterns; if so, flag with SEC-1Severity: WARN | Languages: * | Source: CCC
What it checks: When --history flag is active, scans git commit messages
and diff hunks for evidence that credentials have been previously rotated. If
secrets were rotated in the past, the current secret may still be compromised
if the rotation was incomplete.
Also checks: Presence of expiry dates on secrets where the application supports them (e.g., JWT expiry, API key expiry metadata).
Detection (requires --history flag):
scripts/scan_secrets.sh --path {scope} --historyagent_action:
SEC-6 (WARN): Credential was present in git history at commit {sha}:{file}:{line}.Severity: WARN | Languages: typescript, javascript, python, go | Source: CCC
What it prohibits: CORS configurations that allow all origins (*) in a
production server context. Wildcard CORS on authenticated endpoints effectively
bypasses the Same-Origin Policy.
Prohibited:
// Express
app.use(cors({ origin: '*' }))
res.setHeader('Access-Control-Allow-Origin', '*')
# FastAPI
app.add_middleware(CORSMiddleware, allow_origins=["*"])
Exemptions:
# WAIVER: comment explaining the intentDetection:
cors.*origin.*\*, Allow-Origin.*\*,
allow_origins.*\*agent_action:
SEC-7 (WARN): CORS wildcard at {file}:{line}. Authenticated endpoints must restrict allowed origins.'*' with an explicit allowlist from env config:
origin: process.env.ALLOWED_ORIGINS?.split(',') ?? []--fix: replace wildcard with env-var-driven allowlist# WAIVER: block documenting the intentBLOCK violations (SEC-1 through SEC-4) suspend all other work until resolved. Do not proceed with architecture, naming, or TDD feedback while a SEC BLOCK is active.
Report schema: see skills/conductor/shared-contracts.md.