Skip to main content

Attack-test RL environment graders for reward hacking — a pentest for reward functions.

Project description

gradecheck

Attack-test your RL environment's grader before an RL run does it for you.

RL environments reward whatever the grader accepts — and models optimize the grader, not the task. If the grader has a loophole (delete the failing tests, copy the expected outputs, submit nothing and exit clean), training finds it and you ship a model that learned to cheat. Today those loopholes are caught by a human reading grader code and imagining exploits.

gradecheck makes the known exploits a checklist that runs automatically. You point it at an environment; it plays the laziest, most dishonest agent possible — running a battery of canonical cheap strategies against your grader — and reports which ones were wrongly rewarded:

$ gradecheck run ./my-env

  ⚠ FOOLED   test-deletion  Grader awards full reward (1.000) after deleting 1 test file(s).
  ⚠ FOOLED   test-deletion  Grader awards full reward (1.000) after emptying 1 test file(s).
  △ WARN     answer-leak    1 answer-shaped file(s) reachable from the submission tree.
  ✓ RESISTED noop           Starting tree scores 0.000 (not solved) — correct.
  ✓ RESISTED empty-source   Empty submission scores 0.000 <= baseline 0.000 — correct.

  VULNERABLE — grader fooled by 2 attack(s)

Exit code is 1 when any attack fools the grader, so it drops straight into CI.

It does not catch every possible hack — nothing can. It clears out the known, mechanical loopholes so human review spends its imagination on the novel ones.

Install

pip install gradecheck

Zero dependencies. Python ≥ 3.11. (The verifiers integration below adds one optional dependency and currently wants Python 3.11–3.12.)

Setup

Drop a gradecheck.toml next to your environment:

[env]
name = "my-task"
workspace = "task"                 # the tree the agent edits and submits
source_globs = ["src/**/*.py"]     # files a real fix would touch

[grade]
cmd = "python3 verification/grade.py --task-dir {workspace}"
timeout = 1800
pass_marker = "RESULT: PASS"       # exit 0 + this marker == solved
score = [                          # optional: partial-credit scoreboard lines
  { regex = 'F2P:\s*(\d+)\s*/\s*(\d+)' },
  { regex = 'P2P:\s*(\d+)\s*/\s*(\d+)' },
]

gradecheck copies workspace fresh for every attack, mutates the copy the way a cheating agent would, runs your grade command against it, and compares the reward to the honest baseline. Your environment is never modified.

Attacks

id what it simulates
noop submit the starting tree unchanged — it must not already pass
empty-source blank out the source files — absence must never score higher
test-deletion delete the visible tests, then separately empty them — the pass signal must not depend on tests the agent can rewrite
answer-leak (static) scan the submission tree for reachable gold/expected/answer artifacts an agent could copy
hollow-implementation read the grader's source ([grade].source), extract the string literals/paths it checks for, write a fake artifact containing them, and see if the grader passes without the task being done

Verdicts: FOOLED (grader gave undeserved reward — fix it), WARN (exploit surface a human should confirm), RESISTED (correct behavior).

gradecheck attacks              # list attacks
gradecheck run . --json         # machine-readable report
gradecheck run . --attacks noop,test-deletion

Prime Intellect verifiers environments

Verifiers environments grade a model completion rather than a file tree — the author's reward functions live under env.rubric. gradecheck attacks them directly: it loads the environment, samples real task examples, and scores degenerate completions against the reward functions. No rollout, no Docker, no LLM, no API key.

pip install "gradecheck[verifiers]"
prime env install some-env            # or pip install the env package
gradecheck verifiers some-env --sample 20
  ⚠ FOOLED   flattery       Judge-flattery / correctness assertion: accepted on 3/3 sampled example(s).
  ⚠ FOOLED   prompt-echo    Prompt echoed back: accepted on 3/3 sampled example(s).
  ✓ RESISTED empty-completion Empty completion: rejected on all 3 sampled example(s).
  ✓ RESISTED garbage        Nonsense completion: rejected on all 3 sampled example(s).
  ✓ RESISTED answer-leak    Gold answer not present in the agent's observation.
  · INFO     baseline       Gold answer scores as solved on 3/3 sampled example(s).

Completion attacks: empty-completion, prompt-echo, garbage, flattery (bare assertions of correctness — catches keyword/LLM-judge rewards), and answer-leak (checks whether the gold answer is visible in the agent's own observation, not merely accessible to the reward function). A reward function that accepts any of these is scoring surface form, not correctness.

Writing your own attacks

Attacks are small classes with a registry — subclass gradecheck.attacks.base.Attack, implement run(ctx), and call gradecheck.attacks.register(MyAttack). ctx gives you materialize() (fresh workspace copy), grade(ws), and the honest baseline.

Safety note

gradecheck deliberately submits adversarial trees to your own grader, on your machine, using the grade command you configure. It executes nothing an agent couldn't already make your grader execute — but as with any grading run, do it inside the same sandbox/container your environment normally grades in.

License

Apache-2.0

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

gradecheck-0.1.0.tar.gz (19.2 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

gradecheck-0.1.0-py3-none-any.whl (25.0 kB view details)

Uploaded Python 3

File details

Details for the file gradecheck-0.1.0.tar.gz.

File metadata

  • Download URL: gradecheck-0.1.0.tar.gz
  • Upload date:
  • Size: 19.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.11.28 {"installer":{"name":"uv","version":"0.11.28","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for gradecheck-0.1.0.tar.gz
Algorithm Hash digest
SHA256 b0dd1cd4a0984fcdc96fba0b13fee5ff772736ea8d60c49c7e04aca9ce42813c
MD5 7905a2df74dd84955fb9e81099909877
BLAKE2b-256 35f3633406a7cd1fbe7fb52a03d96d2c170ed6531799a4f8e9140a51e8ebc391

See more details on using hashes here.

File details

Details for the file gradecheck-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: gradecheck-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 25.0 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.11.28 {"installer":{"name":"uv","version":"0.11.28","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for gradecheck-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 87b11db26473e7c5570c5a6c6d7c647b5cfe8d758ba2f6c00fe508ec6e0207b7
MD5 09c39d379595dbb965aaf6235f6dcbfa
BLAKE2b-256 8b2784184f698fa098fe53cd7dec06ee02879392592885071336e72cc02cb40b

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page