fix(pr_agent/agent/pr_agent.py): validating auto command arguments - #2911
fix(pr_agent/agent/pr_agent.py): validating auto command arguments#2911dwin-gharibi wants to merge 2 commits into
Conversation
… a forbidden auto command argument
IsmaelMartinez
left a comment
There was a problem hiding this comment.
Thanks, and the asymmetry you found is real; the revert probe goes properly red here.
The implementation has a false-positive problem though. The denylist substring-matches the whole argument including its value, so ordinary review instructions are silently dropped:
--pr_reviewer.extra_instructions="Flag any hardcoded openai.key in the diff"
--pr_reviewer.extra_instructions="Verify the litellm.base_url override"
--pr_reviewer.extra_instructions="Explain the .system prompt handling"
--pr_reviewer.extra_instructions="Check every config.url is not hardcoded"
All four apply on main today. The tell is not the return value, since a clean argument also returns ['/review']; it is that Updated setting PR_REVIEWER.EXTRA_INSTRUCTIONS never appears.
Matching the key rather than the whole token would keep the protection without the collateral.
| f"Dropping auto-command argument for forbidden param '{offending_arg}'. " | ||
| f"Use instead a configuration file." | ||
| ) | ||
| args = [argument for argument in args |
There was a problem hiding this comment.
This re-validates each argument whole, value included, so --pr_reviewer.extra_instructions whose text merely mentions openai.key, .url, .user, .system or .base_url is dropped along with the genuinely forbidden ones. Splitting on "=" and validating only the key would fix it.
Two smaller things while you are here: only the first offending param is named in the log though all of them are dropped, and "Use instead a configuration file" is carried over from the comment path, where it makes sense; an auto command already comes from one.
Closes #2910.
Description
PRAgent._handle_requestrunsCliArgs.validate_user_argsbefore applying settings.prepare_command, used by the webhook adapters for auto commands, callsupdate_settings_from_argswith no validation at all.Root cause
Scoping, stated honestly: this is hardening, not a live exploit. Auto commands come from settings, and
repo settings are read from
.pr_agent.tomlon the default branch of the base repo(
get_repo_settings()callsget_contents(".pr_agent.toml")with noref), so a fork PR author cannot injectthem. The reachable actor is a maintainer, who already controls the config. What is objectively wrong is that the
same denylist is enforced on one path and skipped on the other — including for
extra_config_url, which pulls aremote TOML a third party may control.
The fix
prepare_commandvalidates the tokenised arguments and drops the individual arguments the denylist rejects, logging which parameter was refused. The command itself still runs.Behaviour change
openai.key,config.secret_providerorconfig.review_pathFiles changed
Testing
Written test-first: the test was committed red, then the fix turned it green.
New regression coverage in
tests/unittest/test_prepare_command_arg_validation.py— 11 tests:Proven to be a genuine regression test: with every changed
pr_agent/file reverted to its739ea8a6version and the new test file left in place, the suite fails. It only passes with the fix applied.
Full unit suite on this branch:
The 3 failures are
tests/unittest/test_extra_config_url.py, which fail identically on unmodifiedmainin thissandbox because they need outbound network; they pass in CI.
Also checked:
ruff— no new findings vsmain;isort— clean on every file touchedRisk / compatibility
Allowed overrides are unaffected, and the quoting behaviour the tokenizer exists to preserve is covered by its own test.