openenv-secaudit / README.md
dexter-2k's picture
Upload folder using huggingface_hub
ee929ba verified
|
Raw
History Blame Contribute Delete
14.9 kB

SecretsAuditEnv

A reinforcement-learning benchmark that drops an AI agent into a git-backed codebase seeded with realistic secret leaks β€” hardcoded API keys, base64-encoded tokens, credentials buried in git history β€” and grades how quickly and safely the agent remediates every one. The environment runs as a stateless FastAPI server; the agent interacts over HTTP with bash commands and structured inspection actions, receiving a composite reward after every step that captures security progress, code health, and time efficiency.

Why This Exists

Production secret leaks remain a top-5 cause of cloud breaches. Developers commit API keys, push .env files, or leave credentials in migration scripts β€” then scramble to rotate and rewrite history. Existing linting tools flag secrets but don't fix them; LLM agents can, but there's no standardized benchmark to measure how well. SecretsAuditEnv fills that gap with a 13-task curriculum spanning trivial single-file fixes to multi-service cascading leaks with git-history rewriting, complete with a deterministic grading pipeline and an anti-gaming reward function.



Task Curriculum

All 13 tasks are defined in tasks/ with full metadata in each task.json. Secret types are detected by graders/security.py using regex patterns for AWS keys, GitHub tokens, Firebase keys, connection strings, private keys, SQL passwords, assignment secrets, and base64-encoded variants.

ID Difficulty Title Description Scan Mode Visibility Tiers Conflict Map
1 Easy Cloud Provisioning Hardcoded AWS Access Key in config.py dir surface, surface, shallow β€”
2 Easy Database Layer Password embedded in a raw SQL connection string dir surface, surface, shallow β€”
3 Easy Frontend Config Firebase API key exposed in a client-side config file dir surface, surface, shallow β€”
4 Easy System Logging Debug logging leaks a user token dir surface, surface, shallow β€”
5 Easy Git Basics A tracked .env file leaks credentials in the working tree dir surface, surface, shallow β€”
6 Medium Utility Module A base64-encoded auth token hides in utils.py dir surface, shallow, deep β€”
7 Medium CI/CD Pipeline A deployment workflow prints a secret directly to logs dir surface, shallow, deep β€”
8 Medium Noise Filtering High-entropy dummy values are mixed with one real secret in TOML dir surface, shallow, deep β€”
9 Medium DB Migration A legacy migration embeds administrator credentials dir surface, shallow, deep β€”
10 Medium Deployment A multiline RSA private key is embedded in a shell script dir surface, shallow, deep β€”
11 Hard Microservices The same API key is duplicated across five services dir surface, deep, cascading βœ“
12 Hard Deep Logic A secret is embedded as a local variable inside a function dir surface, deep, cascading βœ“
13 Hard Legacy Audit A secret was committed in v1.0 and still exists in Git history git surface, deep, cascading βœ“

Scan modes: dir scans the working directory only. git scans the full git commit history (all revisions), so agents must use git filter-repo to clean history β€” deleting files won't work.


Secret Visibility Tiers

Secrets are not all visible at episode start. The environment implements a 4-tier progressive disclosure system defined per-secret in task.json:

Tier When Visible Typical Use
SURFACE Immediately on /reset Obvious hardcoded keys in source files
SHALLOW After agent calls inspect_file <path> Secrets that require reading the file to notice
DEEP After inspect_git_history or inspect_encoded Secrets in git commits or base64-encoded blobs
CASCADING After a specified trigger secret is fixed Secrets that only become relevant after another is remediated

Hard tasks (11–13) include conflict maps that encode dependencies: fixing secret s1 may reveal s3, while s2 may block s3 until resolved.


Reward Formula

Defined in graders/reward.py. Computed fresh after every /step:

detection_score = (initial_leaks - current_leaks) / initial_leaks
base            = 0.4 Γ— detection_score + 0.6 Γ— detection_score     # (remediation = detection for now)
health_score    = pytest_passed / pytest_total                       # 0.0 if errors > 0 or total == 0
efficiency      = 0.15 Γ— max(0, 1 - steps_taken / step_budget)      # decays linearly per step

if base > 0:
    total_reward = min(1.0, base Γ— health_score + efficiency)
else:
    total_reward = 0.0                                               # no free points for doing nothing

Key properties:

  • Reward is 0.0 until the agent actually fixes something β€” read-only commands like cat or ls cannot earn reward
  • Health gate: breaking the test suite (e.g., deleting imports) multiplies reward toward zero
  • Efficiency bonus (0.0–0.15): rewards agents that solve in fewer steps. Decays to 0 at step budget
  • Step budgets: Easy = 10, Medium = 20, Hard = 30

Action Space

Actions are sent as the action field in POST /step. Two categories:

Structured Actions (intercepted before bash)

Action Format Effect
inspect_file inspect_file <path> Marks file as inspected β†’ unlocks SHALLOW secrets for that path
inspect_git_history inspect_git_history [path] Scans git history β†’ unlocks all DEEP secrets requiring git inspection
inspect_encoded inspect_encoded <path> [line] Decodes base64 blobs β†’ unlocks DEEP encoded secrets for that path

Bash Commands (executed in workspace via /usr/bin/bash -lc)

Any string that doesn't match a structured prefix is executed as a bash command in the task workspace. Common patterns:

  • cat config.py β€” read file contents
  • sed -i 's/AKIA.../os.getenv("AWS_KEY")/' config.py β€” redact a secret
  • git filter-repo --replace-text <(echo 'ghp_xxx==>REDACTED') --force β€” clean git history
  • gitleaks detect --no-git --source . β€” run leak scanner

Commands time out after 90 seconds. Exit code, stdout, and stderr are returned in the observation.


Observation Keys

Every /step and /reset response returns a session object with these fields (also listed in openenv.yaml):

Key Type Description
visible_secrets list[dict] Secrets the agent can currently see (filtered by visibility tier)
hidden_count_hint int Number of secrets not yet visible β€” tells agent more exist
ranked_actions list[dict] Top-5 heuristic action suggestions sorted by priority (0.0–1.0)
top_blocker string One-sentence description of the highest-priority next action
step_budget int Total step budget for this difficulty tier
steps_taken int Steps consumed so far
steps_remaining int step_budget - steps_taken
efficiency_bonus float Current efficiency bonus value (decays each step)
conflict_map dict Dependency graph between visible secrets (reveals/blocks relationships)
security_score float Fraction of initial leaks fixed (0.0–1.0)
health_score float Fraction of pytest tests passing (0.0–1.0)
reward float Composite reward after this step
observation string Combined stdout/stderr from last command + health/security messages
last_result dict Raw action, exit_code, stdout, stderr, timed_out from last command

Ranked Actions

Generated by server/observation.py using 5 heuristics:

  1. Visible unfixed secrets β†’ priority 0.92 (fix these first)
  2. Uninspected high-risk files β†’ priority based on filename suspicion score
  3. Git history not yet scanned β†’ priority 0.75 (medium/hard only)
  4. Hidden secrets remaining β†’ priority 0.68 (suggest encoded inspection)
  5. All visible fixed β†’ priority 0.85 (run gitleaks validation)

Quick Start

Local Development

# Install dependencies
pip install -r requirements.txt

# Generate task workspaces
python tools/generate_tasks.py

# Start the server
uvicorn server.app:app --host 0.0.0.0 --port 7860

# Open the debug UI
open http://localhost:7860/web

# Run the agent (requires LLM API)
export API_BASE_URL="https://openrouter.ai/api/v1"
export HF_TOKEN="your-api-key"
export MODEL_NAME="nvidia/nemotron-3-super-120b-a12b:free"
export ENV_URL="http://localhost:7860"
python inference.py --task-id 1

Docker

docker build -t secretsauditenv .
docker run -p 7860:7860 secretsauditenv
# Server auto-generates tasks and starts on port 7860

The Dockerfile installs Python 3.11-slim with bash, git, git-filter-repo, and all pip dependencies. The entrypoint runs tools/generate_tasks.py then starts uvicorn.


inference.py β€” Agent Loop

The baseline agent (inference.py) implements a single-turn ReAct loop over any OpenAI-compatible API:

  1. Reset β€” POST /reset with the target task ID
  2. Prompt β€” Builds a structured prompt from the current session state (reward, leaks, health, last command output, recent actions)
  3. Call LLM β€” Sends prompt to the model, extracts a bash command from the response
  4. Normalize β€” Strips markdown fences, extracts from XML tool_call formats, filters prose prefixes, enforces atomic (no && or ; chaining)
  5. Step β€” POST /step with the action, reads updated state
  6. Repeat until reward >= 1.0 or MAX_STEPS (40) reached

Environment variables:

Variable Required Description
API_BASE_URL Yes OpenAI-compatible API endpoint (e.g., https://openrouter.ai/api/v1)
HF_TOKEN Yes API key for the model provider
MODEL_NAME Yes Model identifier (e.g., nvidia/nemotron-3-super-120b-a12b:free)
ENV_URL No Server URL, defaults to http://localhost:7860
TASK_ID No Default task, overridden by --task-id CLI arg

Anti-loop features:

  • Detects 3 consecutive identical actions with identical rewards β†’ injects a CRITICAL WARNING into the prompt and forces a different command
  • Filters natural language preambles (e.g., "Let me check...", "Looking at...") before sending to bash

Grading Pipeline

Security Grader (graders/security.py)

Custom regex-based scanner (no external tools required). Detects:

  • AWS Access Keys (AKIA...)
  • GitHub tokens (ghp_...)
  • Firebase API keys (AIza...)
  • Service tokens (tok_live_..., sk_test_...)
  • Private keys (PEM format)
  • SQL connection strings (postgres://user:pass@host/db)
  • SQL passwords (PASSWORD 'value')
  • High-entropy assignment secrets (Shannon entropy β‰₯ 3.2)
  • Base64-encoded variants of all the above

Supports .gitleaks.toml allowlists. For scan_mode: git, scans all commits via git rev-list --all.

Anti-gaming: if an agent deletes .git, the grader recovers by creating a fresh snapshot and scanning that β€” the secret still gets found.

Health Grader (graders/health.py)

Runs pytest -q --junitxml in the task workspace and parses the JUnit XML report. Score = passed / total. Returns 0.0 if any errors or if pytest times out (60s default).


Web Debug UI

Available at GET /web. A single-page dark-mode dashboard served from server/web_ui.html that lets you:

  • Start any of the 13 tasks with one click
  • Send structured actions or raw bash commands
  • View real-time metrics (reward, leaks, hidden count, steps, efficiency, health)
  • See ranked action suggestions and conflict maps
  • Browse visible secrets and full observation text
  • Review action history

No external dependencies β€” pure HTML/CSS/JS.


Validation

# Run the environment test suite (34 tests)
python -m pytest tests/ -v

# Run the submission validator (checks connection, Docker build, spec compliance, reward integrity)
bash validate-submission.sh

The validator checks:

  1. Connection β€” /reset returns HTTP 200
  2. Docker portability β€” no absolute host paths leak into the image
  3. Spec compliance β€” spec.md exists, all 13 task directories present, openenv validate passes
  4. Reward integrity β€” smoke test runs inference.py for 2 steps and verifies [START]/[STEP]/[END] log format

Project Structure

.
β”œβ”€β”€ server/
β”‚   β”œβ”€β”€ app.py              # FastAPI routes (/reset, /step, /state, /tasks, /web)
β”‚   β”œβ”€β”€ environment.py      # Core environment logic, visibility tiers, action parsing
β”‚   β”œβ”€β”€ observation.py      # Ranked action heuristics and top_blocker computation
β”‚   └── web_ui.html         # Debug dashboard (served at /web)
β”œβ”€β”€ graders/
β”‚   β”œβ”€β”€ security.py         # Regex-based secret scanner with git history support
β”‚   β”œβ”€β”€ health.py           # Pytest-based health grader with JUnit parsing
β”‚   β”œβ”€β”€ reward.py           # Composite reward: security Γ— health + efficiency
β”‚   β”œβ”€β”€ gitleaks_eval.py    # Spec-aligned wrapper with git integrity reporting
β”‚   └── health_eval.py      # Spec-aligned wrapper with failure messaging
β”œβ”€β”€ tasks/
β”‚   β”œβ”€β”€ easy/task_01..05/   # 5 easy tasks (single-file, surface+shallow secrets)
β”‚   β”œβ”€β”€ medium/task_06..10/ # 5 medium tasks (multi-format, surface+shallow+deep)
β”‚   └── hard/task_11..13/   # 3 hard tasks (cascading, conflict maps, git history)
β”œβ”€β”€ tests/
β”‚   β”œβ”€β”€ test_hidden_leaks.py    # 11 tests: visibility tier logic
β”‚   β”œβ”€β”€ test_ranked_actions.py  # 12 tests: heuristic action suggestions
β”‚   └── test_reward.py         # 11 tests: reward formula and efficiency bonus
β”œβ”€β”€ tools/
β”‚   β”œβ”€β”€ generate_tasks.py   # Generates all 13 task workspaces with seeded secrets
β”‚   β”œβ”€β”€ check_space_ready.py
β”‚   β”œβ”€β”€ prepare_hf_space_bundle.sh
β”‚   └── prepare_github_upload_bundle.sh
β”œβ”€β”€ inference.py            # Baseline LLM agent loop (OpenAI-compatible)
β”œβ”€β”€ openenv.yaml            # OpenEnv spec declaration
β”œβ”€β”€ Dockerfile              # Python 3.11-slim + git + git-filter-repo
β”œβ”€β”€ hf_space_entrypoint.sh  # Docker entrypoint: generate tasks β†’ start uvicorn
β”œβ”€β”€ validate-submission.sh  # 4-check submission validator
β”œβ”€β”€ requirements.txt        # Pip dependencies
β”œβ”€β”€ pyproject.toml          # Package metadata
└── spec.md                 # Environment specification document

License

MIT