JakeChampion / JakeChampion/trafficserver
[audit][standards] Qualified private="field"/no-cache="field" directives are discarded entirely, allowing shared-cache storage of private responses
Nobody has claimed this yet.
- Dominant language
- C++
- Stars
- 0
- Forks
- 0
- Avg merge
- 8h 2m
- Merged PRs (30d)
- 21
Description
Severity: high · Category: standards-gap
Location: src/proxy/hdrs/MIME.cc:3833
What's wrong
In MIMEHdrImpl::recompute_cooked_stuff, after a well-known Cache-Control token is recognized and its mask bit set (line 3765), any trailing non-whitespace content causes the just-set mask bits to be cleared (lines 3833-3841). This 'ignore unrecognized directive' logic (added for issue #12029, semicolon separators) also fires for the RFC-valid qualified forms 'private="Set-Cookie"' and 'no-cache="Set-Cookie"': the token parses as private/no-cache, then c points at '=', which is non-whitespace, so csv_value_mask is reverted. RFC 9111 Section 5.2.2.7 says a shared cache that does not implement the field-name form of private MUST NOT store the response, and Section 5.2.2.4 says the same for no-cache (must not be used without revalidation). ATS instead drops the directive completely: response_cacheable_indicated_by_cc (src/proxy/http/HttpTransact.cc:6561-6563) then sees no CC_PRIVATE bit, so 'Cache-Control: private="Set-Cookie", max-age=600' is judged cacheable (+1 via max-age) and a per-user response can be cached and served to other users. Only the exact string 'private,no-cache' is special-cased on the fastpath (line 3738). There is no unit-test coverage for the qualified forms in src/proxy/hdrs/unit_tests/test_HdrUtils.cc.
Evidence
src/proxy/hdrs/MIME.cc:3830-3841:
while (c < e && ParseRules::is_ws(*c)) { ++c; }
if (c < e) {
// "A cache MUST ignore unrecognized cache directives." (RFC 7234 5.2)
if (csv_value_mask != 0) {
m_cooked_stuff.m_cache_control.m_mask &= ~csv_value_mask;
}
}
src/proxy/http/HttpTransact.cc:6561-6563:
cc_mask = MIME_COOKED_MASK_CC_PRIVATE | (ignore_no_store_and_no_cache_directives ? 0 : MIME_COOKED_MASK_CC_NO_STORE);
if (response->get_cooked_cc_mask() & cc_mask) { return -1;
Suggested fix
In the trailing-content check, special-case directives whose qualified (field-name argument) form is defined by RFC 9111 — private and no-cache — and fall back to treating them as unqualified (keep the mask bit set) instead of clearing it. Add unit tests for 'Cache-Control: private="Set-Cookie"' and 'no-cache="Set-Cookie"' asserting CC_PRIVATE/CC_NO_CACHE remain set.
Filed from an automated multi-lens codebase audit. Full report: CODEBASE_AUDIT.md / audit-report.html on branch claude/codebase-audit-review-9nw7vz.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start in src/proxy/hdrs/MIME.cc at MIMEHdrImpl::recompute_cooked_stuff and review the trailing-content handling around lines 3833-3841, then inspect response_cacheable_indicated_by_cc in src/proxy/http/HttpTransact.cc. Run the relevant tests in src/proxy/hdrs/unit_tests/test_HdrUtils.cc. Done means qualified private and no-cache directives retain their expected mask bits and the new cases pass.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- cpp
- Domain
- networking
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 78/100