Authentication confusion

Following a duplicated parameter across a trust boundary, one parser at a time.

The challenge

This fictional local exercise has two components: a request validator and a small application. Both read the same URL. The question is whether they agree on what that URL means.

No live target, real event, or recovered flag is associated with this example. All inputs below can be inspected locally.

Reconnaissance

Consider an input with two values for the same key:

GET /profile?role=reader&role=editor HTTP/1.1
Host: localhost

The repeated key is the entire experiment. One hypothetical component chooses the first value; another chooses the last.

ComponentInterpretationResult
ValidatorFirst valuereader
ApplicationLast valueeditor
Strict parserReject duplicatesinvalid request
A request reaches two parsers with conflicting interpretations

The discrepancy

The following Python snippet demonstrates the ambiguity without making a network request:

from urllib.parse import parse_qs

query = "role=reader&role=editor"
values = parse_qs(query)["role"]

validator_role = values[0]
application_role = values[-1]

print(validator_role, application_role)
assert validator_role != application_role
reader editor

This is a model of parser disagreement, not proof that a particular framework is vulnerable. Actual behavior depends on the complete request path.

A local regression check

A deterministic fix for this toy example is to reject duplicate security-sensitive fields. Authorization should also use server-held identity and permissions, rather than a caller-supplied role.

def require_single_value(query, key):
    values = parse_qs(query, keep_blank_values=True).get(key, [])
    if len(values) != 1:
        raise ValueError("Expected exactly one value")
    return values[0]

try:
    require_single_value("role=reader&role=editor", "role")
except ValueError:
    print("Ambiguous input rejected")
Additional cases for the local test suite
  • An omitted key.
  • An empty value.
  • Two identical values.
  • Percent-encoded key names.
  • Differences between query parameters and request body fields.

Lessons learned

The useful result is an explicit parsing contract. Record which layer rejects ambiguity, how the application consumes the normalized input, and what a regression test proves.

A surprising response is a starting point. A reproducible explanation is the deliverable.