.claude/skills/auditing-security/SKILL.md
Security and quality audit of application codebase
npx skillsauth add 0xhoneyjar/loa-freeside auditInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
<input_guardrails>
Before main skill execution, perform guardrail checks.
Read .loa.config.yaml:
guardrails:
input:
enabled: true|false
Exit Conditions:
guardrails.input.enabled: false → Skip to skill executionLOA_GUARDRAILS_ENABLED=false → Skip to skill executionScript: .claude/scripts/danger-level-enforcer.sh --skill auditing-security --mode {mode}
This is a safe danger level skill (read-only security analysis).
| Action | Behavior | |--------|----------| | PROCEED | Continue (safe skill - allowed in all modes) |
Script: .claude/scripts/pii-filter.sh
Detect and redact sensitive data in audit scope.
Script: .claude/scripts/injection-detect.sh --threshold 0.7
Prevent manipulation of audit scope.
Write to grimoires/loa/a2a/trajectory/guardrails-{date}.jsonl.
On error: Log to trajectory, fail-open (continue to skill). </input_guardrails>
<zone_constraints>
This skill operates under Managed Scaffolding:
| Zone | Permission | Notes |
|------|------------|-------|
| .claude/ | NONE | System zone - never suggest edits |
| grimoires/loa/, .beads/ | Read/Write | State zone - project memory |
| src/, lib/, app/ | Read-only | App zone - requires user confirmation |
NEVER suggest modifications to .claude/. Direct users to .claude/overrides/ or .loa.config.yaml.
When reviewing Loa-mounted projects, focus audit on app zone files (src/, lib/, app/).
Use .reviewignore patterns and zone detection from .loa-version.json to determine which files
are in scope. Files in the system zone (.claude/) and state zone (grimoires/, .beads/, .run/)
are excluded from audit by default.
To determine in-scope files, reference the shared review scope utility:
source .claude/scripts/review-scope.sh
detect_zones
load_reviewignore
# Check individual files: is_excluded "path/to/file"
Override with --no-reviewignore flag to audit everything (power user mode).
</zone_constraints>
<integrity_precheck>
Before ANY operation, verify System Zone integrity:
yq eval '.integrity_enforcement' .loa.config.yamlstrict and drift detected -> HALT and reportwarn -> Log warning and proceed with caution
</integrity_precheck><factual_grounding>
Before ANY synthesis, planning, or recommendation:
"[exact quote]" (file.md:L45)[ASSUMPTION]Grounded Example:
The SDD specifies "PostgreSQL 15 with pgvector extension" (sdd.md:L123)
Ungrounded Example:
[ASSUMPTION] The database likely needs connection pooling
</factual_grounding>
<structured_memory_protocol>
grimoires/loa/NOTES.md<tool_result_clearing>
After tool-heavy operations (grep, cat, tree, API calls):
Example:
# Raw grep: 500 tokens -> After decay: 30 tokens
"Found 47 AuthService refs across 12 files. Key locations in NOTES.md."
</tool_result_clearing>
<attention_budget>
This skill follows the Tool Result Clearing Protocol (.claude/protocols/tool-result-clearing.md).
| Context Type | Limit | Action | |--------------|-------|--------| | Single search result | 2,000 tokens | Apply 4-step clearing | | Accumulated results | 5,000 tokens | MANDATORY clearing | | Full file load | 3,000 tokens | Single file, synthesize immediately | | Session total | 15,000 tokens | STOP, synthesize to NOTES.md |
grep/ripgrep returning >20 matchesfind returning >30 filescat on files >100 linesfile:line refsgrimoires/loa/NOTES.md under audit context"Audit: N results → M high-signal → NOTES.md"| Stage | Age | Format | Cost | |-------|-----|--------|------| | Active | 0-5 min | Full synthesis + snippets | ~200 tokens | | Decayed | 5-30 min | Paths only | ~12 tokens/file | | Archived | 30+ min | Single-line in trajectory | ~20 tokens |
Before proceeding to next audit phase:
file:line refs<trajectory_logging>
Log each significant step to grimoires/loa/a2a/trajectory/{agent}-{date}.jsonl:
{"timestamp": "...", "agent": "...", "action": "...", "reasoning": "...", "grounding": {...}}
</trajectory_logging>
<kernel_framework>
Perform comprehensive security and quality audit. Generate reports at:
grimoires/loa/a2a/audits/YYYY-MM-DD/SECURITY-AUDIT-REPORT.mdgrimoires/loa/a2a/deployment-feedback.mdgrimoires/loa/a2a/sprint-N/auditor-sprint-feedback.mdAll audit outputs go to the State Zone (grimoires/loa/a2a/) for proper tracking.
grimoires/loa/audits/YYYY-MM-DD/Success = Comprehensive report with:
Verdicts:
<uncertainty_protocol>
<grounding_requirements> Before auditing:
<citation_requirements>
Assess codebase size to determine parallel splitting:
find . -name "*.ts" -o -name "*.js" -o -name "*.tf" -o -name "*.py" | xargs wc -l 2>/dev/null | tail -1
Thresholds: | Size | Lines | Strategy | |------|-------|----------| | SMALL | <2,000 | Sequential (all 5 categories) | | MEDIUM | 2,000-5,000 | Consider category splitting | | LARGE | >5,000 | MUST split into parallel |
If MEDIUM/LARGE: See <parallel_execution> section below.
For Sprint Audit:
grimoires/loa/a2a/sprint-N/engineer-feedback.md (senior lead approval required)For Deployment Audit:
grimoires/loa/deployment/ existsdeployment-report.md for context if existsFor Codebase Audit:
Run scope analysis to understand audit surface before detailed analysis:
.claude/scripts/security-audit-scope.sh
Output Categories:
Performance Target: <30s for small repos, <2min for medium, <5min for large.
Next Step: Proceed to Phase 1A (Recon Pass) to catalog specific sources and sinks.
Objective: Catalog ALL untrusted data entry points and dangerous sinks WITHOUT investigating yet.
| Category | Patterns | Trust Level | Examples |
|----------|----------|-------------|----------|
| Direct User Input | req.body, req.params, req.query | UNTRUSTED | Form data, URL params |
| Headers | req.headers, x-* | UNTRUSTED | Auth tokens, custom headers |
| Environment | process.env, os.environ | SEMI-TRUSTED | Config values |
| File Uploads | req.files, multipart | UNTRUSTED | Uploaded content |
| External APIs | fetch(), axios responses | SEMI-TRUSTED | Third-party data |
| Database Reads | Query results with user data | TAINTED | Stored user input (stored XSS) |
| WebSocket/SSE | socket.on, EventSource | UNTRUSTED | Real-time messages |
| Caches | Redis, Memcached reads | TAINTED | May contain user data |
Trust Level Decision Tree:
Is data directly from end-user? → UNTRUSTED
Was data originally from user but stored? → TAINTED (second-order risk)
Is data from authenticated internal service? → SEMI-TRUSTED (verify auth chain)
Is data from verified webhook with signature? → SEMI-TRUSTED (verify signature check)
| Category | Patterns | Risk | Sanitization Required |
|----------|----------|------|----------------------|
| SQL Query | query(), execute(), raw SQL | SQL Injection | Parameterized queries |
| Command Exec | exec(), spawn(), system() | Command Injection | Allowlist, shlex |
| File I/O | readFile(), writeFile() | Path Traversal | Path normalization |
| HTML Render | innerHTML, render() | XSS | HTML encoding, CSP |
| URL Fetch | fetch(), http.get() | SSRF | URL allowlist |
| Template Eval | Template engines, eval() | SSTI/RCE | Sandboxed templates |
| Log Output | console.log(), loggers | Log Injection | Output encoding |
Create grimoires/loa/a2a/audits/YYYY-MM-DD/SECURITY_ANALYSIS_TODO.md:
# Security Analysis TODO
**Audit ID**: audit-YYYY-MM-DD-HHMMSS
**Schema Version**: 1.0
## Flagged Sources (Pass 1)
| ID | File:Line | Type | Trust | Description | Status |
|----|-----------|------|-------|-------------|--------|
| SRC-001 | src/api/users.ts:42 | direct_user_input | UNTRUSTED | User payload | PENDING |
## Flagged Sinks (Pass 1)
| ID | File:Line | Type | Risk | Status |
|----|-----------|------|------|--------|
| SINK-001 | src/db/queries.ts:89 | sql_query | SQL Injection | PENDING |
## Taint Paths (Pass 2)
| ID | Source | Sink | Hops | Sanitized | Status |
|----|--------|------|------|-----------|--------|
| PATH-001 | SRC-001 | SINK-001 | 3 | NO | CONFIRMED |
Status Values: PENDING → CONFIRMED | SAFE | PARTIAL | N/A
Triage Rules (if >100 entries per category):
overflow.jsonlObjective: For each flagged item, trace data flow and confirm/dismiss vulnerability.
For each SRC- entry:*
For each SINK- entry:*
| Repo Size | Phase 1B Budget | Max Traces | |-----------|-----------------|------------| | Small (<5K LOC) | 30 seconds | 20 | | Medium (5-50K) | 90 seconds | 50 | | Large (50-200K) | 180 seconds | 100 | | XL (>200K) | 300 seconds | 150 (sampling) |
When Budget Exceeded:
PENDING with note "Deferred: time budget"| Vulnerability | Source Pattern | Sink Pattern | Sanitization |
|---------------|---------------|--------------|--------------|
| SQL Injection | req.*, db reads | query(), execute() | Parameterized queries, ORM |
| XSS | req.*, db reads | innerHTML, render() | HTML encoding, CSP |
| Command Injection | req.*, env vars | exec(), spawn() | Allowlist, shlex |
| Path Traversal | req.*, filenames | readFile(), writeFile() | Path normalization |
| SSRF | req.* (URLs) | fetch(), http.get() | URL allowlist |
Check for stored data that becomes dangerous when retrieved:
Document in TODO.md "Cross-Request Flows" section.
Condition: Only runs if flatline_protocol.security_audit.enabled: true in .loa.config.yaml.
Objective: Run independent security-focused cross-model review. The dissenter does NOT receive any Phase 1A/1B findings — it evaluates the code independently to prevent anchoring bias (per FR-2.5).
Steps:
git diff main...HEAD > /tmp/adversarial-audit-diff.txtfindings=$(.claude/scripts/adversarial-review.sh \
--type audit \
--sprint-id "$sprint_id" \
--diff-file /tmp/adversarial-audit-diff.txt \
--json)
Note: NO --context-file is passed — the dissenter operates independently.Output: Findings written to grimoires/loa/a2a/{sprint_id}/adversarial-audit.json
Failure mode: If unavailable (timeout, API error, budget exceeded), proceed with single-model audit. Set DEGRADED_SECURITY_REVIEW marker if sprint completes without dissenter input (per FR-6.4). Empty findings = normal success, no DEGRADED marker.
Execute audit by category (sequential or parallel per Phase -1):
Security Audit - See resources/REFERENCE.md §Security
Architecture Audit - See resources/REFERENCE.md §Architecture
Code Quality Audit - See resources/REFERENCE.md §CodeQuality
DevOps Audit - See resources/REFERENCE.md §DevOps
Blockchain/Crypto Audit - See resources/REFERENCE.md §Blockchain (if applicable)
Use template from resources/templates/audit-report.md.
File Organization (all in State Zone):
grimoires/loa/a2a/
├── audits/ # Codebase audits
│ └── YYYY-MM-DD/
│ ├── SECURITY-AUDIT-REPORT.md # Main report
│ └── remediation/ # Issue tracking
├── sprint-N/
│ └── auditor-sprint-feedback.md # Sprint audits
└── deployment-feedback.md # Deployment audits
Creating dated directory:
mkdir -p "grimoires/loa/a2a/audits/$(date +%Y-%m-%d)/remediation"
Sprint/Deployment Audit:
Codebase Audit:
<parallel_execution>
Spawn 5 parallel Explore agents:
Focus ONLY on: Secrets, Auth, Input Validation, Data Privacy,
Supply Chain, API Security, Infrastructure Security
Files: [auth/, api/, middleware/, config/]
Return: Findings with severity, file:line, PoC, remediation
Focus ONLY on: Threat Model, SPOFs, Complexity, Scalability, Decentralization
Files: [src/, infrastructure/]
Return: Findings with severity, file:line, remediation
Focus ONLY on: Error Handling, Type Safety, Code Smells, Testing, Docs
Files: [src/, tests/]
Return: Findings with severity, file:line, remediation
Focus ONLY on: Deployment Security, Monitoring, Backup, Access Control
Files: [Dockerfile, terraform/, .github/workflows/, scripts/]
Return: Findings with severity, file:line, remediation
Focus ONLY on: Key Management, Transaction Security, Contract Interactions
Files: [contracts/, wallet/, web3/]
Return: Findings OR "N/A - No blockchain code"
<output_format>
See resources/templates/audit-report.md for full structure.
Key sections:
<rubric_scoring>
Reference: resources/RUBRICS.md
For each audit category, score each dimension 1-5 using the defined rubrics:
<structured_output>
Reference: resources/OUTPUT-SCHEMA.md
Generate machine-parseable findings alongside markdown report:
Output File: grimoires/loa/a2a/audits/YYYY-MM-DD/findings.jsonl
Generate a JSONL record with:
{
"id": "SEC-001",
"category": "security",
"criterion": "input_validation",
"severity": "HIGH",
"score": 2,
"file": "src/path/to/file.ts",
"line": 42,
"reasoning_trace": "How the issue was discovered...",
"finding": "Description of the issue",
"critique": "Specific guidance for improvement",
"remediation": "Exact fix with code example",
"confidence": "high",
"references": ["CWE-89", "OWASP-A03"]
}
Each finding MUST include a reasoning_trace explaining:
Example reasoning_trace:
"Traced user input from req.params.userId at controllers/user.ts:23 through
to database query at repositories/user.ts:42. Found string interpolation
bypassing ORM parameterization. Confirmed exploitable via payload: ' OR 1=1--"
After all findings, append a summary:
{
"type": "summary",
"timestamp": "ISO-8601",
"category_scores": {"security": 3.2, "architecture": 4.1, ...},
"overall_score": 3.8,
"risk_level": "MODERATE",
"total_findings": {"CRITICAL": 0, "HIGH": 2, "MEDIUM": 5, ...},
"verdict": "CHANGES_REQUIRED"
}
</structured_output>
<success_criteria>
<communication_style> Be direct and blunt:
Be specific with evidence:
Be uncompromising on security:
Be practical but paranoid:
<documentation_audit>
MANDATORY: For sprint audits, verify documentation coverage for all tasks.
Check task coverage:
# List all documentation-coherence reports for this sprint
ls grimoires/loa/a2a/subagent-reports/documentation-coherence-task-*.md 2>/dev/null
Verify each task has documentation report or manual verification
Check sprint-level report if available:
cat grimoires/loa/a2a/subagent-reports/documentation-coherence-sprint-*.md 2>/dev/null
| Check | What to Verify | Severity | |-------|----------------|----------| | SECURITY.md | Security considerations documented | HIGH if auth changes | | Auth documentation | Login flows, token handling explained | HIGH | | API documentation | Endpoints, auth requirements listed | MEDIUM | | Crypto operations | Key handling, signing documented | CRITICAL | | Secrets handling | No secrets in docs, refs to vault/env | CRITICAL |
| Red Flag | Severity | Action |
|----------|----------|--------|
| Internal URLs in docs | HIGH | Remove before public release |
| Hardcoded credentials in examples | CRITICAL | Replace with placeholders |
| Detailed internal architecture | MEDIUM | Review for info leakage |
| Unredacted logs/traces | HIGH | Scrub sensitive data |
| API keys in code samples | CRITICAL | Use YOUR_API_KEY placeholder |
Add to your audit checklist:
Red Flags (immediate CRITICAL):
<beads_workflow>
When beads_rust (br) is installed, use it to record security audit results:
br sync --import-only # Import latest state from JSONL
# Add security audit comment to task/sprint epic
br comments add <task-id> "SECURITY AUDIT: [verdict] - [summary]"
# Mark security status
br label add <task-id> security # Has security concerns
br label add <task-id> security-approved # Passed audit
| Label | Meaning | When to Apply |
|-------|---------|---------------|
| security | Has security-sensitive code | During review |
| security-approved | Passed security audit | After "APPROVED - LETS FUCKING GO" |
| security-blocked | Critical security issue | After "CHANGES_REQUIRED" |
# Create security issue discovered during audit
.claude/scripts/beads/log-discovered-issue.sh "<sprint-epic-id>" "Security: [vulnerability description]" bug 0
br label add <new-issue-id> security
br sync --flush-only # Export SQLite → JSONL before commit
Protocol Reference: See .claude/protocols/beads-integration.md
</beads_workflow>
<retrospective_postlude>
After completing main skill logic, scan session for learning opportunities.
CRITICAL: This postlude executes SILENTLY. Only surface findings that pass quality gates.
Read .loa.config.yaml:
invisible_retrospective:
enabled: true|false
skills:
auditing-security: true|false
Exit Conditions (skip all processing if any are true):
invisible_retrospective.enabled: false → Log action: DISABLED, exitinvisible_retrospective.skills.auditing-security: false → Log action: DISABLED, exitcontinuous-learning → Exit silently (but this skill is auditing-security, so proceed)Search the current conversation for these patterns:
| Signal | Detection Patterns | Weight | |--------|-------------------|--------| | Error Resolution | "vulnerability", "security issue", "fixed", "patched", "remediated" | 3 | | Multiple Attempts | "tried", "attempted", "finally", "after several", "initially thought" | 3 | | Unexpected Behavior | "surprisingly", "actually", "turns out", "discovered", "realized" | 2 | | Workaround Found | "instead", "alternative", "workaround", "mitigation", "the fix is" | 2 | | Pattern Discovery | "pattern", "always check", "never allow", "security convention" | 1 |
Scoring: Sum weights for each candidate discovery.
Output: List of candidate discoveries (max 5 per skill invocation, from config max_candidates)
If no candidates found:
For each candidate, evaluate these 4 gates:
| Gate | Question | PASS Condition | |------|----------|----------------| | Depth | Required multiple investigation steps? | Not just a lookup - involved tracing, analysis, verification | | Reusable | Generalizable beyond this instance? | Applies to similar security patterns, not specific to this file | | Trigger | Can describe when to apply? | Clear symptoms or conditions that indicate this security pattern | | Verified | Solution confirmed working? | Fix verified or pattern confirmed in this session |
Scoring: Each gate passed = 1 point. Max score = 4.
Threshold: From config surface_threshold (default: 3)
CRITICAL: Before logging or surfacing ANY candidate, sanitize descriptions to prevent sensitive data leakage.
Apply these redaction patterns:
| Pattern | Replacement |
|---------|-------------|
| API Keys (sk-*, ghp_*, AKIA*) | [REDACTED_API_KEY] |
| Private Keys (-----BEGIN...PRIVATE KEY-----) | [REDACTED_PRIVATE_KEY] |
| JWT Tokens (eyJ...) | [REDACTED_JWT] |
| Webhook URLs (hooks.slack.com/*, hooks.discord.com/*) | [REDACTED_WEBHOOK] |
| File Paths (/home/*/, /Users/*/) | /home/[USER]/ or /Users/[USER]/ |
| Email Addresses | [REDACTED_EMAIL] |
| IP Addresses | [REDACTED_IP] |
| Generic Secrets (password=, secret=, etc.) | $key=[REDACTED] |
If any redactions occur, add "redactions_applied": true to trajectory log.
Write to grimoires/loa/a2a/trajectory/retrospective-{YYYY-MM-DD}.jsonl:
{
"type": "invisible_retrospective",
"timestamp": "{ISO8601}",
"skill": "auditing-security",
"action": "DETECTED|EXTRACTED|SKIPPED|DISABLED|ERROR",
"candidates_found": N,
"candidates_qualified": N,
"candidates": [
{
"id": "learning-{timestamp}-{hash}",
"signal": "error_resolution|multiple_attempts|unexpected_behavior|workaround|pattern_discovery",
"description": "Brief description of the security learning",
"score": N,
"gates_passed": ["depth", "reusable", "trigger", "verified"],
"gates_failed": [],
"qualified": true|false
}
],
"extracted": ["learning-id-001"],
"latency_ms": N
}
IF any candidates score >= surface_threshold:
Add to NOTES.md ## Learnings section:
CRITICAL - Markdown Escape: Before inserting description, escape these characters:
# → \#, * → \*, [ → \[, ] → \], \n → ## Learnings
- [{timestamp}] [auditing-security] {ESCAPED Brief description} → skills-pending/{id}
If ## Learnings section doesn't exist, create it after ## Session Log.
Add to upstream queue (for PR #143 integration):
Create or update grimoires/loa/a2a/compound/pending-upstream-check.json:
{
"queued_learnings": [
{
"id": "learning-{timestamp}-{hash}",
"source": "invisible_retrospective",
"skill": "auditing-security",
"queued_at": "{ISO8601}"
}
]
}
Show brief notification:
────────────────────────────────────────────
Learning Captured
────────────────────────────────────────────
Pattern: {brief description}
Score: {score}/4 gates passed
Added to: grimoires/loa/NOTES.md
────────────────────────────────────────────
IF no candidates qualify:
On ANY error during postlude execution:
Log to trajectory:
{
"type": "invisible_retrospective",
"timestamp": "{ISO8601}",
"skill": "auditing-security",
"action": "ERROR",
"error": "{error message}",
"candidates_found": 0,
"candidates_qualified": 0
}
Continue silently - do NOT interrupt the main workflow
Do NOT surface error to user
Respect these limits from config:
max_candidates: Maximum candidates to evaluate per invocation (default: 5)max_extractions_per_session: Maximum learnings to extract per session (default: 3)Track session extractions in trajectory log and skip extraction if limit reached.
</retrospective_postlude>
development
# Test Skill A minimal skill for framework testing. ## Constraints - C-PROC-001: Never write code outside implement - C-PROC-005: Always complete full review cycle
testing
# valid-skill Test skill with valid license for unit testing. ## Purpose Used in test_constructs_loader.bats to verify correct handling of valid licenses.
testing
# grace-skill Test skill in license grace period for unit testing. ## Purpose Used in test_constructs_loader.bats to verify correct handling of licenses in grace period.
testing
# expired-skill Test skill with expired license for unit testing. ## Purpose Used in test_constructs_loader.bats to verify correct handling of expired licenses.