Skip to content

fix(security): block PasswordHash bypass via whole-WebUI section replace#283

Merged
cursor[bot] merged 2 commits into
masterfrom
cursor/bug-finding-automation-7bbb
Jun 22, 2026
Merged

fix(security): block PasswordHash bypass via whole-WebUI section replace#283
cursor[bot] merged 2 commits into
masterfrom
cursor/bug-finding-automation-7bbb

Conversation

@cursor

@cursor cursor Bot commented Jun 18, 2026

Copy link
Copy Markdown
Contributor

Summary

PR #271 blocked dotted-key WebUI.PasswordHash writes, but section-level WebUI object replacement in ApplyDottedConfigChanges bypassed that guard. An attacker with the API token could clear PasswordHash and re-bootstrap POST /web/auth/set-password using WebUI.Token alone — enabling account takeover.

Root cause: RejectPasswordHashConfigChange only inspected dotted keys named exactly WebUI.PasswordHash. Top-level section replace ({"changes": {"WebUI": {..., "PasswordHash": ""}}}) never hit that check before save.

Fix: Added WebUIAuthHelpers.ValidatePasswordHashForConfigApiSave() as a centralized save-time guard. Restores [redacted] placeholder from current config; rejects any other PasswordHash change. Applied in Host SaveAndRespondConfigUpdate (covers /web/config and /api/config) and WebUI /web/config + /web/config/save.

Closed PR #276 proposed the same fix but was never merged.

Testing

  • PostConfig_WithWholeWebUISectionEmptyPasswordHash_Returns403_AndPreservesLogin — regression for section-level bypass
  • ValidatePasswordHashForConfigApiSave_* unit tests
  • Existing ConfigRedactionTests pass
  • dotnet test tests/Torrentarr.Host.Tests/ --filter ConfigRedactionTests|WebUIAuthHelpersTests
  • dotnet test tests/Torrentarr.Infrastructure.Tests/ --filter WebUIAuthHelpersTests

Checklist

  • Ran tests
  • Confirmed there are no sensitive secrets or credentials committed
Open in Web View Automation 

PR #271 blocked dotted-key WebUI.PasswordHash writes, but section-level
WebUI object replacement in ApplyDottedConfigChanges bypassed that guard.
An attacker with the API token could clear PasswordHash and re-bootstrap
set-password using WebUI.Token alone.

Add ValidatePasswordHashForConfigApiSave as a save-time invariant in Host
SaveAndRespondConfigUpdate and WebUI config save paths. Regression test
confirms section-level replace returns 403.

Co-authored-by: Feramance <Feramance@users.noreply.github.com>
…fig save

Co-authored-by: Feramance <Feramance@users.noreply.github.com>
@cursor cursor Bot marked this pull request as ready for review June 22, 2026 13:30
@cursor cursor Bot merged commit e3845a4 into master Jun 22, 2026
8 checks passed

@cursor cursor Bot left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

PR Validation (Cursor Automation)

Recommendation: Merge
Primary reason: Clean post-merge validation: no conflicts, release build passed, non-live .NET tests passed, and Vitest passed. GitHub currently reports this PR as MERGED.

Gates

Gate Status Notes
Merge conflicts Pass cursor/bug-finding-automation-7bbb merged cleanly with current origin/master; conflicts: none.
dotnet build Pass dotnet build -c Release succeeded with 18 warnings and 0 errors after installing pinned SDK 10.0.100 into /tmp/dotnet for this runner.
dotnet test (non-live) Pass dotnet test -c Release --no-build --filter "Category!=Live": 766 passed, 0 failed, 0 skipped. Test count is above the stated baseline.
vitest Pass npx vitest run: 16 files passed, 154 tests passed.
npm run build (webui) N/A The PR did not modify the React webui/ source tree, so this conditional gate was not required.

Validation

Axis Score Notes
Purpose Pass Addresses a real remaining config-auth gap after #271: section/full-object WebUI replacement could still alter PasswordHash.
Correctness Pass Adds a centralized save-time invariant in WebUIAuthHelpers and applies it to Host/WebUI config save paths while preserving [redacted] placeholder behavior.
Tests Pass Adds host regression coverage for whole-WebUI replacement and helper unit coverage; full non-live test totals did not drop.
Hygiene Pass Narrow 5-file scope; no generated build output, SDK junk, temp docs, or unrelated noise.
Overlap Pass Not a duplicate of #271: #271 fixed dotted-key writes, while this PR covers section/full-object replacement. #276 proposed similar coverage but is closed/unmerged.

Why

The fix is aligned with the Torrentarr-specific Auth/WebUI rule that WebUI.PasswordHash must only be set via POST /web/auth/set-password. The implementation rejects direct hash changes at save time, so bypasses that avoid dotted-key validation are also blocked. The PR is already merged according to GitHub, but the locally merged validation tree builds and tests cleanly.

Required audit note: docs/audits/pr-triage-*.md was not present in this checkout, so overlap was checked using the 2026-06-15 winner table from the automation prompt plus gh pr view/gh pr list.

Overlap

None. Related PRs checked: #271 is merged and narrower; #276 is closed/unmerged.

Commands run

  • git fetch origin master
  • git fetch origin cursor/bug-finding-automation-7bbb
  • git checkout -B pr-validate origin/cursor/bug-finding-automation-7bbb
  • git merge origin/master
  • git diff --name-status origin/master...origin/cursor/bug-finding-automation-7bbb
  • gh pr view 283 --json ...
  • gh pr view 271 --json ...
  • gh pr view 276 --json ...
  • gh pr list --state open --search "PasswordHash" --json ...
  • dotnet restore
  • dotnet build -c Release
  • dotnet test -c Release --no-build --filter "Category!=Live"
  • cd webui && npm ci && npx vitest run
Open in Web View Automation 

Sent by Cursor Automation: Torrentarr PR validation triage

@cursor cursor Bot left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Bug Scan Summary (automation)

Date: 2026-06-22
Commits inspected: 3f2c16f..98fd421 (2 commits)
Result: No critical bugs found in this diff. The change correctly closes the auth bypass.

What was verified

ValidatePasswordHashForConfigApiSave is now invoked on every config-save path before disk write:

  • Host SaveAndRespondConfigUpdate (covers POST /web/config and POST /api/config)
  • WebUI POST /web/config (after FlatToConfig)
  • WebUI POST /web/config/save

The save-time guard catches section-level WebUI replacement (and any other merge path) that bypasses the per-key RejectPasswordHashConfigChange check. [redacted] is restored from the current config; any other hash change returns 403.

Regression coverage

  • PostConfig_WithWholeWebUISectionEmptyPasswordHash_Returns403_AndPreservesLogin exercises the reported bypass vector.
  • WebUIAuthHelpersTests.ValidatePasswordHashForConfigApiSave_* cover reject / restore / unchanged cases.
  • All 6 ConfigRedactionTests pass; full non-live suite passes on master (596 .NET tests).

Deduplication

  • Open PRs: searched PasswordHash, auth bypass, section replace — no competing fix PRs.
  • Recently merged: #271, #258, and this PR (e3845a4 on master) — this is the intended fix for the whole-WebUI bypass (#271 only blocked dotted keys).
  • Open issues: no duplicate tracking issues found.

No additional changes recommended from this scan.

Open in Web View Automation 

Sent by Cursor Automation: Torrentarr - Find critical bugs

cursor Bot pushed a commit that referenced this pull request Jun 22, 2026
Inspects all open PRs (#280-#283, #285, #292-#293, #296, #300) with
local CI-equivalent checks, per-PR verdicts, merge order, and #280
feature-slice breakdown.

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Feramance <Feramance@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant