Skip to content

Refs #576: Reject control chars in payout notes#627

Closed
xingxi0614-cpu wants to merge 1 commit into
ramimbo:mainfrom
xingxi0614-cpu:codex/b576-payout-note-controls
Closed

Refs #576: Reject control chars in payout notes#627
xingxi0614-cpu wants to merge 1 commit into
ramimbo:mainfrom
xingxi0614-cpu:codex/b576-payout-note-controls

Conversation

@xingxi0614-cpu
Copy link
Copy Markdown

@xingxi0614-cpu xingxi0614-cpu commented May 29, 2026

Refs #576

Summary

Reject raw control characters in admin payout note values before trimming them into public verifier metadata.

This keeps values such as these from being accepted as clean notes during bounty payout proposal creation:

  • note="<tab>verified manually"
  • note="verified manually\x85"

Blank whitespace-only notes are still omitted, and ordinary space-padded notes are still trimmed before being stored.

Distinctness

This is limited to the admin payout API note field before it becomes verifier/proposal metadata. It does not overlap the existing #576 slices for attempt source_url, MRWK amount strings, treasury proposal fields, webhook identities, wallet material, account/wallet/bounty filters, MCP arguments, JSON integers, forwarded proto headers, or deploy settings.

Validation

Safety

No private data, secrets, admin token values, wallet material, production mutation, price/liquidity/exchange/bridge/off-ramp claims, or fabricated payout claims are included.

Summary by CodeRabbit

  • Bug Fixes
    • Control character validation for note fields now runs on raw input before whitespace processing.
    • Note content is truncated to a maximum of 240 characters when non-empty.

Review Change Stack

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 29, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: d7e5a4d8-c220-48ac-99e8-d261a101ee73

📥 Commits

Reviewing files that changed from the base of the PR and between 0708f8a and 365095e.

📒 Files selected for processing (2)
  • app/bounty_api.py
  • tests/test_security.py

📝 Walkthrough

Walkthrough

This PR adjusts note field validation in the bounty payout API. Control-character validation now runs against the raw input before whitespace stripping, and the note is included in the result only if the stripped value is non-empty. The security test is expanded to parameterized form, covering multiple control-character cases.

Changes

Note Field Validation

Layer / File(s) Summary
Note validation in api_pay_bounty
app/bounty_api.py
api_pay_bounty validates control characters against raw input before stripping whitespace, then includes the stripped note in the result only if non-empty and under 240 characters.
Control-character validation tests
tests/test_security.py
test_admin_payout_api_rejects_control_character_note becomes a parameterized test covering multiline, tabbed, and DEL-like control characters, verifying consistent 400 rejection across all variants.
🚥 Pre-merge checks | ✅ 6
✅ Passed checks (6 passed)
Check name Status Explanation
Title check ✅ Passed The title directly names the changed surface (control character rejection in payout notes) and references the related issue.
Description check ✅ Passed The description covers the summary, evidence of validation testing, safety considerations, and scope boundaries; all critical sections are present and substantive.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Mergework Public Artifact Hygiene ✅ Passed No investment, price, cash-out, fabricated payout claims, or private security details found. Code change is purely technical input validation for control characters in admin payout notes.
Bounty Pr Focus ✅ Passed Changes limited to payout note field: control char validation on raw input before stripping, parameterized test with three scenarios, no unrelated modifications detected.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@barnacleagent-svg barnacleagent-svg left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PR Review — #627

PR: #627
Author: @xingxi0614-cpu
Head SHA: 365095e

Files Changed (2 files)

  • : Moved control-char check before strip() so raw note is checked, not trimmed note
  • : Parametrized test to cover
    , , and � control chars

CI Status

Quality/readiness/docs/image checks: completed/success

Code Review

  • Fix is correct: checking raw_note before strip() ensures tab/� at start/end are caught
  • Parameterized test cleanly covers all three control patterns
  • No side effects, no stale references

Verdict

APPROVE — Ready for merge.

@peterxing
Copy link
Copy Markdown

Reviewed current head 365095e9a9d2dc73eafb5bf83354ce0f64b1301c as a non-author.

Verdict: no blocker found in this slice.

Evidence checked:

  • inspected the diff in app/bounty_api.py and tests/test_security.py;
  • verified the control-character check now runs against raw_note before .strip(), so leading tabs and trailing C1 controls cannot be normalized into clean verifier notes;
  • verified whitespace-only and ordinary padded notes still keep the previous behavior: empty after trim is omitted, non-empty clean text is trimmed and capped at 240 characters;
  • checked that the regression expands the existing note test with newline, tab-prefixed, and \x85 suffixed inputs, matching the intended failure cases;
  • checked PR metadata: open, non-draft, mergeable, two changed files, and CodeRabbit reports no actionable comments with focused bounty scope passing.

I did not run local tests in this automation pass because the hourly loop is currently avoiding package/test execution unless strictly necessary. No private data, secrets, admin token values, wallet material, production mutation, signing, transfers, price/liquidity/exchange/bridge/off-ramp claims, or fabricated payout claims were used.

Copy link
Copy Markdown

@Jorel97 Jorel97 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed current head 365095e9a9d2dc73eafb5bf83354ce0f64b1301c as a non-author.

Evidence checked:

  • Inspected app/bounty_api.py and tests/test_security.py.
  • Verified raw_note is checked with CONTROL_CHAR_RE before .strip(), so leading tabs/newlines and trailing C1 controls are rejected instead of normalized into clean verifier metadata.
  • Verified ordinary whitespace-only notes still omit the note after trimming, and clean padded notes still trim before the existing 240-character cap.
  • Verified the regression parametrizes newline, leading tab, and trailing \x85 cases through the admin payout API.
  • Checked hosted metadata: PR is open, non-draft, mergeable/clean, and the quality/readiness check plus CodeRabbit status are green.

Local validation on Windows:

  • .\.venv\Scripts\python.exe -m pytest tests\test_security.py -q -> 57 passed, 1 Starlette/httpx deprecation warning.
  • .\.venv\Scripts\python.exe -m ruff check app\bounty_api.py tests\test_security.py -> passed.
  • .\.venv\Scripts\python.exe -m ruff format --check app\bounty_api.py tests\test_security.py -> 2 files already formatted.
  • .\.venv\Scripts\python.exe -m mypy app\bounty_api.py -> success.
  • git diff --check origin/main...HEAD -> clean.
  • git merge-tree --write-tree origin/main HEAD -> clean merge tree 19287c0b64811b4d58a5852f72b615bce00d9b70.

Verdict: APPROVED ? focused input-hardening fix for payout notes with regression coverage and no merge/test hygiene blockers found. No private data, credentials, wallet material, production mutation, signing, transfers, price/liquidity/exchange/bridge/off-ramp claims, or fabricated payout claims used.

@ramimbo
Copy link
Copy Markdown
Owner

ramimbo commented May 30, 2026

Closing this as a #576 claim. #576 is closed/exhausted, so new work under that round is not accepted or payable. If this behavior is still needed, please route it through a narrow proposed-work or future bounty path; it will not be stretched retroactively into #576.

@ramimbo ramimbo closed this May 30, 2026
@ramimbo ramimbo added the mrwk:rejected Submission rejected label May 30, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

mrwk:rejected Submission rejected

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants