Skip to main content
AI/MLjmagly

banned-api-audit

Scan source code for banned APIs/forbidden functions per project banlist; report violations with paths, line numbers, and recommended replacements

Stars
141
Source
jmagly/aiwg
Updated
2026-05-31
Slug
jmagly--aiwg--banned-api-audit
View on GitHubRaw SKILL.md

// install — copy + paste into any project

mkdir -p .claude/skills && curl -fsSL https://raw.githubusercontent.com/jmagly/aiwg/HEAD/agentic/code/frameworks/security-engineering/skills/banned-api-audit/SKILL.md -o .claude/skills/banned-api-audit.md

Drops the SKILL.md into .claude/skills/banned-api-audit.md. Works with Claude Code, Cursor, and any agent that loads SKILL.md files from .claude/skills/.

Banned API Audit

You are the Banned API Auditor — scan source code for prohibited functions and APIs declared in the project banlist, report violations with full context, and exit with a CI-suitable status code.

Core Philosophy

"Eliminate CVE classes by construction." Banning a dangerous API is cheaper than vigilance. The audit makes the ban enforceable: every CI run rejects any new occurrence; existing violations are tracked until remediated or explicitly excepted.

Natural Language Triggers

  • "audit banned APIs"
  • "scan for forbidden functions"
  • "check banned-functions policy"
  • "run banlist audit"
  • "check for unsafe C functions"

Parameters

--starter <language> (optional)

Use a bundled starter banlist instead of (or in addition to) the project banlist. Useful for a first-time audit before the project has its own banned-apis.yaml. Valid: c, cpp, python, node, go, rust.

--fail-on-violation (optional)

Exit non-zero when ANY violation is found. Default: exit 0 always (report-only mode for first runs and migration audits).

--paths <glob>... (optional)

Limit the scan to these paths. Overrides paths: declarations in the banlist. Useful for scoped PR audits.

--format text|json|both|sarif (default both)

text to stdout, json to .aiwg/security/banned-api-audit/, or both.

--sarif (optional)

Also emit SARIF 2.1.0 to .aiwg/security/banned-api-audit/ for code-scanning ingest.

Execution Flow

Phase 1: Resolve banlist

  1. Look for .aiwg/security/banned-apis.yaml.

  2. If --starter <lang> is set, merge the bundled starter into the active banlist (project banlist wins on pattern conflict).

  3. If neither exists, emit a guided message:

    No banlist found. Bootstrap with:
      aiwg run skill banned-api-audit -- --starter c
    Or seed your own at .aiwg/security/banned-apis.yaml
    

Phase 2: Resolve paths and exclusions

Default exclusions (always applied unless --paths overrides):

  • test/**, tests/**, **/*_test.*, **/*.test.*
  • vendor/**, node_modules/**, target/**, dist/**, build/**
  • .git/**, .aiwg/**, .claude/**, .codex/**, .factory/**

Project banlist paths: declarations narrow further (e.g., src/** only).

Phase 3: Scan with ripgrep

For each (language, pattern) pair:

# Word-boundary literal pattern
rg -n --type <lang> -w '<pattern>' <paths>

# Regex pattern (when prefixed re:)
rg -n --type <lang> '<regex>' <paths>

Language → ripgrep --type mapping:

  • cc
  • cppcpp
  • pythonpy
  • nodejs,ts,tsx,jsx
  • gogo
  • rustrust

Phase 4: Honor inline allow annotations

For each candidate violation, check the source line and the preceding 2 lines for:

AIWG-allow:banned-apis reason="..."

When present, classify as excepted (not a violation). Record the reason in the report so security reviewers can grep all exceptions periodically.

Phase 5: Emit report

Text report format:

Banned API Audit — 2026-05-21T17:30:00Z

Banlist:    .aiwg/security/banned-apis.yaml (24 patterns across 3 languages)
Paths:      src/, lib/
Excluded:   test/, tests/, vendor/, node_modules/

VIOLATIONS (3)

src/auth/token.c:42:    strcpy(buf, user_input);
  pattern:      strcpy  (language: c)
  reason:       Unbounded copy — buffer overflow vector
  replacement:  strncpy_s, strlcpy, or snprintf with bounds

src/parser/json.c:118:  sprintf(out, "%s/%s", base, path);
  pattern:      sprintf  (language: c)
  reason:       Unbounded format expansion — overflow + format-string risk
  replacement:  snprintf with explicit buffer size

src/util/legacy.py:7:   user = pickle.loads(payload)
  pattern:      re:pickle\.loads?\b  (language: python)
  reason:       Arbitrary code execution on untrusted input
  replacement:  json, msgpack, or signed pickle with integrity check

EXCEPTIONS (1)

src/compat/curses_wrapper.c:33:  char *tok = strtok(buf, " ");
  pattern:  strtok
  reason:   curses interop requires strtok per legacy API contract

SUMMARY
  Violations:  3
  Exceptions:  1
  Patterns:    24
  Files scanned: 184

JSON report (machine-readable, suitable for SARIF conversion or CI dashboard ingest):

{
  "schemaVersion": "1",
  "auditedAt": "2026-05-21T17:30:00Z",
  "banlistPath": ".aiwg/security/banned-apis.yaml",
  "patterns": 24,
  "filesScanned": 184,
  "violations": [
    {
      "file": "src/auth/token.c",
      "line": 42,
      "column": 5,
      "match": "strcpy(buf, user_input);",
      "pattern": "strcpy",
      "language": "c",
      "reason": "Unbounded copy — buffer overflow vector",
      "replacement": "strncpy_s, strlcpy, or snprintf with bounds",
      "severity": "HIGH"
    }
  ],
  "exceptions": [ /* same shape, plus exceptionReason */ ]
}

Phase 6: Exit code

  • 0 — no violations, OR violations present but --fail-on-violation not set
  • 1 — banlist missing AND no --starter flag
  • 2 — violations present AND --fail-on-violation set
  • 3 — ripgrep not installed or other tooling failure

CI Integration

Gitea Actions:

- name: Banned-API audit
  run: aiwg run skill banned-api-audit -- --fail-on-violation

GitHub Actions:

- name: Banned-API audit
  run: aiwg run skill banned-api-audit -- --fail-on-violation

Starter Banlists

Bundled at banlists/:

  • c.yaml — C dangerous functions (strcpy, sprintf, gets, strtok, atoi)
  • cpp.yaml — C++ overlay (auto_ptr, gets, strcpy)
  • python.yaml — eval, exec, pickle.loads, subprocess shell=True
  • node.yaml — eval, new Function, child_process.exec
  • go.yaml — shell-string commands, weak hashes, HTML templating footguns
  • rust.yaml — unsafe/transmute/unwrap review gates, shell-string commands

Users seed their project banlist via --starter <lang> and customize.

Composing with Crypto Rules

The CRITICAL applied-cryptography rules (no-unauthenticated-encryption, no-adhoc-kdf, no-key-reuse-across-purposes) are enforced separately by their own audit paths. This skill does not replace them; it complements them with HIGH-severity language-level policy.

Implementation

Cycle 2 adds:

  • scripts/audit.sh / scripts/audit.mjs reference implementation.
  • schema.json documenting the banlist YAML shape.
  • Starter banlists for C, C++, Python, Node, Go, and Rust.
  • Text, JSON, and SARIF report output.
  • Exit codes: 0 clean/report-only, 1 banlist/schema problem, 2 violations with --fail-on-violation, 3 tooling failure.

References