security: round 6 re-audit (2026-05-20)#1
Open
RelativisticJet wants to merge 1 commit into
Open
Conversation
…audit) Round-6 security re-audit ran the fuzz suite with 2× example counts (500→1000, 300→600, 200→400) to increase coverage against edge cases. All 19 tests passed with no falsifying examples. Keeping the higher counts permanently: the test-suite wall-clock delta is ~5 s (27 s baseline → 33 s), well within CI budget.
RelativisticJet
added a commit
that referenced
this pull request
May 22, 2026
…BP/CII deferrals Three follow-throughs on the post-hash-pinning state from this session: 1) `.github/dependabot.yml` now declares a second `pip` ecosystem block scoped to `/requirements`, so the 4 hashed lockfiles (test.txt, docs.txt, pip-audit.txt, appinspect.txt) get the same weekly auto-bump treatment that root requirements-dev.txt and the workflow SHA pins already get. Without this, Dependabot would silently skip the new lockfiles — the very files that the previous commit (24f2815) created to satisfy Scorecard's pipCommand-hash-pin criterion. The pip ecosystem only scans `.txt` (not `.in`); maintainers must regen `.in` after a Dependabot PR merge or the next manual regen would undo the bump. Comment block in dependabot.yml + requirements/README.md document the workflow. 2) `docs/DECISION_LOG.md` gains a row for the 2026-05-22 Baseline Branch Protection choice. The GitHub UI's dismissal rationales on alerts #1 (BranchProtectionID) + #74 (CodeReviewID) record the same decision but live in runtime state — the project-internal canonical record belongs in DECISION_LOG. Captures the four options considered (none / baseline+dismiss / full+bypass / full+strict) and the rationale for picking baseline-with-dismiss-with-rationale. Explicit re-evaluation trigger documented: co-maintainer joins OR community contribution volume justifies the friction. 3) `docs/DECISION_LOG.md` gains a parallel row for the CIIBestPractices (`bestpractices.dev`) badge deferral. Captures the three options (apply-now / defer-with-rationale / ignore) and the rationale: the application requires demonstrating ongoing OSS-governance practices a single-maintainer pre-1.0 project does not yet have signal for; applying now would likely return "needs more activity" and burn the badge maintainers' review budget. Re-evaluation trigger: 3+ external contributors with merged PRs, OR Splunkbase install count ≥50, OR an inbound user asks for the badge as a deployment-approval gate. These three follow-throughs close the soft TODOs from the prior turn's "What you can do next" summary. Future Dependabot PRs are now correctly scoped; future re-evaluations of the dismissed Scorecard criteria have explicit triggers + canonical project record outside the GitHub Code Scanning UI. Doc-drift check passes.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
$(cat <<'EOF'
Round 6 Security Re-Audit — 2026-05-20
Auditor: Claude Code (automated re-audit agent)
Scope: All 7 prescribed checks against the hardened codebase, post build-629 / post-hardening-track-close.
Baseline: Security hardening track closed 2026-04-29 at build 629. This is the first re-audit after closure.
What changed since 2026-04-29
Notable security-relevant commits:
d267ea3fix(replay): revert_csv handler delegates to revert_csv_pipeline (build 663) — structural correctness fix in approval replay path301dcd5chore(lookups): trim demo CSVs, docstring-only change to wl_handler.pybin/wl_handler.pywas not functionally modified in this period (confirmed by CHANGELOG note and diff review).Per-Check Results
Check 1 — Unit Tests: ✅ PASS
Required packages not pre-installed:
pytest,hypothesis,freezegun— all installed from PyPI before run. All 833 tests pass including:test_ascii_validation.py(75 tests) — all PASStest_validator_fuzz.py(19 tests) — all PASStest_frontend_backend_parity.py(28 tests) — all PASSCheck 2 — Extended Fuzz: ✅ PASS (2× example count)
@settings(max_examples=500)→ 1000,300→ 600,200→ 400 for this run. The increased counts are committed permanently (5 s wall-clock delta, within CI budget).No falsifying examples found. All stability, determinism, contract, and cross-validator consistency properties hold.
Check 3 — E2E Stress Tests:⚠️ SKIPPED
No Splunk container available in this execution environment. Tests not run:
test_concurrent_save_race.cjstest_trash_traversal.cjstest_rate_limit_burst.cjsThese require a live Splunk container and are covered by the nightly E2E workflow (
.github/workflows/e2e-full.yml).Check 4 — Bypass Flag Grep: ✅ CLEAN
Full search across all bin/ modules also clean:
_from_approvalappears only as Python function parameters / internal kwargs (_from_approval=True), never aspayload.get("_from_*"). The comment atwl_handler.py:3033–3041explicitly documents the old bypass pattern and confirms its removal.Unit test gates confirming this:
TestNoDualApprovalPayloadBypass::test_no_payload_read_of_flag_in_handler— PASSTestNoUnderscoreFlagPayloadBypass::test_handler_has_no_from_flag_reads— PASSTestNoUnderscoreFlagPayloadBypass::test_other_bin_modules_have_no_from_flag_reads— PASSCheck 5 — New POST_ACTIONS: ✅ CLEAN
bin/wl_handler.pyhad only two commits in the audit window, both non-functional:301dcd5— docstring change only (example CSV name updated)da30df6— docs-only commit, no handler changesPOST_ACTIONS dispatch table (lines 1372–1419) is unchanged. All 19 actions verified to have appropriate role gates:
EDIT_ROLES— CSV/rule modifications, approval submissions ✓ADMIN_ROLES— approval processing, trash, usage reset ✓SUPERADMIN_ROLES— limits, lockdown, deploy window, factory reset ✓None— public-to-authenticated (cancel_request, mark_notifications_read, log_event) ✓Spot-checked
_action_save_csv,_action_create_rule,_action_remove_rule,_action_submit_approval: all callvalidate_ascii_texton free-text fields,is_ascii_name/is_safe_filename/is_valid_app_contexton entity-name fields, have length caps, and emit audit events.Check 6 — New Bin Files: ✅ CLEAN (no new files)
Git shallow clone (50 commits, earliest 2026-05-18) shows the initial commit includes all 24 bin/*.py files. No new bin/ files were added since the prior audit. The
d267ea3wl_replay.pyfix refactored existing code; no new module was introduced.STRIDE pass on
wl_replay.py(most recently modified runtime module):original_analystandapproving_admincome from the server-side approval context, not from the user payloadupdate_csv_expected_hashpost_audit_eventstr(e)from exceptions propagated in error dict returned to admin callers (ADMIN_ROLES gate); could leak filesystem paths to adminsresolve_csv_pathbefore any file operation_from_approval=Trueis set internally by the approval path onlyFindings
🟡 MEDIUM —
_execute_replay_create_csvwrites MAPPING_FILE withoutupdate_csv_expected_hashor atomic temp+renameLocation:
bin/wl_replay.py:434–452Description:
When a
create_csvapproval is processed,_execute_replay_create_csvappends a row torule_csv_map.csvusing a directopen(..., "w")+csv.DictWriterwrite. It does not callupdate_csv_expected_hash(MAPPING_FILE)afterwards, and the write is not atomic (no temp+rename pattern).By contrast, the canonical
write_mapping()inbin/wl_rules.py:280–311(used bydelete_rule_pipeline,delete_csv_pipeline) writes atomically via temp+rename and callsupdate_csv_expected_hash(MAPPING_FILE)to keep the FIM registry in sync.Impact:
create_csvapproval executes, the FIM hash forrule_csv_map.csvwill be stale. The next FIM sweep (15 s or ~2 s depending on watcher) will detect a hash mismatch and fire afim_csv_modifiedsecurity alert — a false positive. Repeated alerts erode trust in the FIM signal (alert fatigue).rules_rmw_lock()serialises concurrent writers.Note: this is a structural regression from the
revert_csvfix pattern. The_execute_replay_revert_csvhandler was correctly refactored (build 663) to delegate torevert_csv_pipeline, but_execute_replay_create_csvstill has its own mapping-write logic and was not updated at the same time.Recommended fix:
Accepted state check: this is NOT on the accepted-as-known-good list.
_approval_queue.jsonmissing HMAC is deferred, but the mapping file already has FIM coverage — this is a gap in the replay path only.🔵 LOW —
get_user()falls through to header-based usernameLocation:
bin/wl_rbac.py:140–144Description:
After trying
request["session"]["user"](Splunk's standard auth),get_user()falls back torequest["headers"]["X-Splunk-User-Name"]orrequest["headers"]["Remote-User"]. If the session dict is absent/empty, the username would be drawn from HTTP headers.In Splunk's internal REST framework these headers are set by the infrastructure proxy and are not directly injectable by browser clients. However, the fallback is not documented and may surprise future contributors.
Recommendation: add a comment explaining the trust model (e.g., "headers are populated by Splunk's internal proxy, not from client HTTP headers"), and consider logging a warning when the session fallback is used in production.
Items Verified as Accepted Known-Good State (not flagged)
Per audit instructions, the following are confirmed present but intentionally accepted:
_approval_queue.jsonis not HMAC-signed — deferred to round 6+ ✓ (still deferred, no regression)get_appsendpoint open to all authenticated users ✓cross_app_csv_readaudit event fires before the 404 check ✓Infrastructure Notes
pytest,hypothesis,freezegunnot pre-installed in the execution environment; installed viapip installbefore running tests. This should be added to the dev requirements if not already present inrequirements-dev.txt.--since='2026-04-29'git queries therefore show all bin/ files as "added" in the visible history window, which is an artifact of the shallow clone rather than actual new files. New-file detection was confirmed by inspecting the git log commit messages and comparing against the known stable set of bin/ modules._from_*bypass) were verified manually via grep equivalents.EOF
)
Generated by Claude Code