Skip to content

v3/control: replace unchecked type asserts in DecodeControl with comma-ok#589

Merged
cpuschma merged 2 commits into
go-ldap:masterfrom
c-tonneslan:fix/decode-control-safe-asserts
May 17, 2026
Merged

v3/control: replace unchecked type asserts in DecodeControl with comma-ok#589
cpuschma merged 2 commits into
go-ldap:masterfrom
c-tonneslan:fix/decode-control-safe-asserts

Conversation

@c-tonneslan
Copy link
Copy Markdown
Contributor

Closes #561.

`DecodeControl` assumes every controlType is a string and every criticality is a bool, and the default `ControlString` case casts `value.Value.(string)` unconditionally. When a malformed or hostile server returns a non-string (or nil) in any of these positions, the cast panics the caller's goroutine — the repro in #561 hit the default case where `value.Value` was nil:

```
panic: interface conversion: interface {} is nil, not string
go-ldap/ldap/v3.DecodeControl(...)
go-ldap/ldap/v3.(*Conn).SimpleBind(...)
```

Switched every cast to comma-ok form, returning a clear error when the assertion fails. In the default `ControlString` branch I fall back to `value.Data.String()` when `value.Value` isn't a string, so the application gets the raw bytes instead of a crash.

Existing `TestDecodeControl` table still passes; the new behaviour only kicks in on input that previously panicked.

…a-ok

DecodeControl trusts that every controlType is a string and every
criticality is a bool, and falls back to value.Value.(string) for any
unknown control type. When a malformed or hostile server returns a
non-string (or nil) in any of these positions, the .(string) /
.(bool) cast panics inside the caller's goroutine. The user repro in
go-ldap#561 hit the default case where value.Value was nil:

	panic: interface conversion: interface {} is nil, not string
	  go-ldap/ldap/v3.DecodeControl(...)
	  go-ldap/ldap/v3.(*Conn).SimpleBind(...)

Use comma-ok asserts at every control-frame field, return clear
errors when the cast fails, and in the default ControlString case
fall back to value.Data.String() when value.Value isn't a string so
the application gets the bytes instead of a crash.

The existing TestDecodeControl table covers the normal-path cases
and still passes; the new behaviour only kicks in on malformed
input where the previous code panicked.

Closes go-ldap#561

Signed-off-by: Charlie Tonneslan <cst0520@gmail.com>
@cpuschma cpuschma added enhancement go Pull requests that update go code labels May 16, 2026
@cpuschma cpuschma self-assigned this May 16, 2026
@cpuschma
Copy link
Copy Markdown
Member

@c-tonneslan Thank you for your PR Could you extend the current test suite for the controls to cover your addition?

Covers the new error paths (non-string control type in the 1/2/3-child
cases, non-bool criticality in the 3-child case) and the
ControlString fallback when value.Value isn't a string. All four would
have panicked before go-ldap#589.

Signed-off-by: Charlie Tonneslan <cst0520@gmail.com>
@c-tonneslan
Copy link
Copy Markdown
Contributor Author

Done, pushed a follow-up commit with table-driven cases for the new error paths (non-string control type in each of the 1/2/3-child branches and non-bool criticality in the 3-child branch) plus a positive test for the ControlString fallback when value.Value isn't a string. Each one would've panicked before this PR.

@cpuschma cpuschma merged commit 5877c85 into go-ldap:master May 17, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement go Pull requests that update go code

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Unsafe interface casts in DecoceControl may result PANICs

2 participants