TRANSPARENCY: This is an AI-assisted submission – Aikido
Summary
The generated WISPr setter reads the nested TLV header from vsa[0:2] on every loop iteration instead of from the current cursor vsa[j:j+2]. When the target attribute follows another nested attribute, the old value is not removed and the replacement is appended; first-match lookup therefore continues returning the stale value.
Description
An incoming RADIUS Vendor-Specific Attribute may contain multiple nested WISPr attributes. If application code uses the public WISPr Set or SetString API to sanitize or override one of those attributes, the setter fails when the target is not the first nested attribute. The original value remains before the appended replacement, and the corresponding Lookup/Get API returns the original value. In applications that rely on these setters for trusted replacement or sanitization, this can preserve a peer-controlled redirection or logoff URL and bypass the intended policy. The defect is also emitted by the vendor generator and appears in other generated vendor helpers, so fixing only the WISPr generated file would not prevent regeneration from reintroducing it.
Risk
An attacker controlling a valid RADIUS peer packet can place an unrelated nested vendor attribute before a target WISPr attribute. If the receiving application invokes a WISPr Set/SetString method before consuming or forwarding the packet, the original target remains first and is returned by Lookup/Get. Exploitation depends on that application-level sanitization or override logic.
Evidence
1
The setter advances j and validates against vsa[j:], but repeatedly reads the nested type and length from offset zero. A target after the first nested TLV is therefore skipped and remains in the packet.
for j := 0; len(vsa[j:]) >= 3; {
vsaTyp, vsaLen := vsa[0], vsa[1]
...
if vsaTyp == typ {
vsa = append(vsa[:j], vsa[j+int(vsaLen):]...)
}
j += int(vsaLen)
}
2
Lookup returns the first matching nested attribute, so the stale target left before the appended replacement remains authoritative.
for len(vsa) >= 3 {
vsaTyp, vsaLen := vsa[0], vsa[1]
...
if vsaTyp == typ {
return vsa[2:int(vsaLen)], true
}
vsa = vsa[int(vsaLen):]
}
3
The generator emits the same offset-zero reads into generated vendor setters, propagating the defect beyond WISPr and allowing regeneration to restore it.
p(w, ` for j := 0; len(vsa[j:]) >= 3; {`)
p(w, ` vsaTyp, vsaLen := vsa[0], vsa[1]`)
...
p(w, ` j += int(vsaLen)`)
4
Public WISPr setters route through the defective shared helper, making the replacement failure reachable through the package API.
func WISPrLocationID_Set(p *radius.Packet, value []byte) (err error) {
...
return _WISPr_SetVendor(p, 1, a)
}
Root Cause Analysis
The loop condition and length validation use vsa[j:], showing that j is intended to identify the current nested-attribute offset, but the type and length reads remain anchored at offset zero. With an unrelated first TLV and a target second TLV, the loop repeatedly interprets the first TLV and never removes the target. _WISPr_SetVendor then appends the new target. Because _WISPr_LookupVendor scans from the beginning and returns the first matching type, it returns the original target before the replacement, making the caller's Set operation ineffective. The same generator emission and pattern exist in the Aruba, Microsoft, and Mikrotik generated helpers.
Remediation
In the generated setter and in radius/dictionarygen/vendor.go, read the nested header relative to the cursor: vsaTyp, vsaLen := vsa[j], vsa[j+1]. Keep cursor handling consistent when removing an entry so every nested attribute is examined exactly once. Regenerate all affected vendor helpers and add a regression test with an unrelated nested attribute before the target, asserting that Set followed by Lookup returns only the replacement.
TRANSPARENCY: This is an AI-assisted submission – Aikido
Summary
The generated WISPr setter reads the nested TLV header from vsa[0:2] on every loop iteration instead of from the current cursor vsa[j:j+2]. When the target attribute follows another nested attribute, the old value is not removed and the replacement is appended; first-match lookup therefore continues returning the stale value.
Description
An incoming RADIUS Vendor-Specific Attribute may contain multiple nested WISPr attributes. If application code uses the public WISPr Set or SetString API to sanitize or override one of those attributes, the setter fails when the target is not the first nested attribute. The original value remains before the appended replacement, and the corresponding Lookup/Get API returns the original value. In applications that rely on these setters for trusted replacement or sanitization, this can preserve a peer-controlled redirection or logoff URL and bypass the intended policy. The defect is also emitted by the vendor generator and appears in other generated vendor helpers, so fixing only the WISPr generated file would not prevent regeneration from reintroducing it.
Risk
An attacker controlling a valid RADIUS peer packet can place an unrelated nested vendor attribute before a target WISPr attribute. If the receiving application invokes a WISPr Set/SetString method before consuming or forwarding the packet, the original target remains first and is returned by Lookup/Get. Exploitation depends on that application-level sanitization or override logic.
Evidence
1
The setter advances j and validates against vsa[j:], but repeatedly reads the nested type and length from offset zero. A target after the first nested TLV is therefore skipped and remains in the packet.
2
Lookup returns the first matching nested attribute, so the stale target left before the appended replacement remains authoritative.
3
The generator emits the same offset-zero reads into generated vendor setters, propagating the defect beyond WISPr and allowing regeneration to restore it.
4
Public WISPr setters route through the defective shared helper, making the replacement failure reachable through the package API.
Root Cause Analysis
The loop condition and length validation use vsa[j:], showing that j is intended to identify the current nested-attribute offset, but the type and length reads remain anchored at offset zero. With an unrelated first TLV and a target second TLV, the loop repeatedly interprets the first TLV and never removes the target. _WISPr_SetVendor then appends the new target. Because _WISPr_LookupVendor scans from the beginning and returns the first matching type, it returns the original target before the replacement, making the caller's Set operation ineffective. The same generator emission and pattern exist in the Aruba, Microsoft, and Mikrotik generated helpers.
Remediation
In the generated setter and in radius/dictionarygen/vendor.go, read the nested header relative to the cursor: vsaTyp, vsaLen := vsa[j], vsa[j+1]. Keep cursor handling consistent when removing an entry so every nested attribute is examined exactly once. Regenerate all affected vendor helpers and add a regression test with an unrelated nested attribute before the target, asserting that Set followed by Lookup returns only the replacement.