Repository navigation
Bug: NSEC bitmap serializer omits URI record type 256, causing incorrect signed denial and API/wire mismatch #2244
Description
Summary
Technitium DNS Server 15.6.2 appears to contain an NSEC type-bitmap serialisation defect affecting DNS record type URI (256).
A DNSSEC-signed authoritative zone can serve an NSEC bitmap that incorrectly omits URI, despite URI records being present and correctly signed.
Following a normal Update Record operation, the primary's records API and textual zone export include URI in the NSEC type list, but authoritative UDP/TCP responses and secondary zone transfers continue to omit it.
Investigation of the release-matched TechnitiumLibrary source identified a likely off-by-one/window-presence defect in DnsNSECRecordData.WriteTypeBitMapsTo.
Suspected root cause
Source:
DnsNSECRecordData.cs — dns-server-v15.6.2
The method surveys each NSEC type-bitmap window using its highest bit offset:
if (windowBlockSurvey[windowBlockNumber] < bitNumber)
windowBlockSurvey[windowBlockNumber] = bitNumber;It then only emits windows where:
if (maxBits > 0)URI has DNS resource record type 256, corresponding to:
Window number:
1Bit offset:
0
When URI is the only record type in window 1, the maximum bit offset remains zero. This is indistinguishable from an absent window under the current condition.
Consequently, the serializer can omit window 1 entirely.
The correct encoded bitmap window should contain:
01 01 80The NSEC object also maintains a logical Types collection separate from the serialised _rData bytes.
This potentially explains why:
API and textual zone export display URI correctly.
DNSSEC signing processes serialised bytes without URI.
Authoritative DNS answers omit URI.
Zone transfers propagate the URI-omitting representation.
The release-matched source and the observed behaviour strongly support this explanation. However, the exact deployed TechnitiumLibrary DLL has not been independently verified as binary-equivalent to the reviewed source.
The same suspect source condition was also observed in the master branch during investigation.
Environment
Technitium DNS Server: 15.6.2
Two authoritative DNS servers configured as primary and secondary
DNSSEC signing: NSEC
Existing signed zone with dynamically maintained records
URI record sets containing four members
URI priority:
0URI weight:
100TTL:
3600
Production hostnames, addresses and credentials have been omitted.
Observed behaviour
At an internal owner equivalent to:
_kerberos.test.invalid.The zone contains TXT and URI RRsets. Four URI records exist and resolve correctly.
The correct NSEC type bitmap is:
TXT RRSIG NSEC URIBefore maintenance, both authoritative servers instead returned:
TXT RRSIG NSECURI was incorrectly omitted.
Maintenance test
One documented POST /api/zones/records/update request was executed on the primary, reapplying an existing URI member with unchanged:
Owner name
URI target
Priority and weight
TTL
Enabled state
Expiry configuration
The API returned HTTP 200 and status: ok.
The zone SOA advanced monotonically. All four original URI records, positive DNS values, TTLs and DNSKEYs were preserved.
Results after the update
Source | NSEC type bitmap -- | -- Primary records API | TXT RRSIG NSEC URI Primary textual zone export | TXT RRSIG NSEC URI Primary authoritative UDP | TXT RRSIG NSEC Primary authoritative TCP | TXT RRSIG NSEC Secondary records API/export | TXT RRSIG NSEC Secondary authoritative UDP/TCP | TXT RRSIG NSECThe discrepancy persisted across repeated read-only checks.
Importantly:
The NSEC RRSIG successfully verifies against the URI-omitting authoritative wire representation.
The same signature fails verification against the primary's URI-inclusive text-export representation.
The URI RRset itself remains correctly signed and verifiable.
The secondary successfully refreshed and converged its SOA and current signatures, but retained the incorrect bitmap.
No additional authoritative wire-level fault or client outage was demonstrated.
The result suggests the NSEC object retains URI in its logical type collection while its serialised representation omits the corresponding bitmap window.
Suggested minimal reproduction
In an isolated test installation:
Create a DNSSEC-signed NSEC zone, such as
test.invalid.Create an owner
_kerberos.test.invalidcontaining a TXT record and URI records.Use URI type 256 as the only type in bitmap window 1.
Compare the records API and zone-file export against direct authoritative NSEC responses.
Update an existing URI record without changing its values using the documented Update Record API.
Repeat the comparison and verify the NSEC RRSIG against both representations.
Optionally transfer the zone to a secondary and inspect its resulting bitmap.
For a smaller unit test, exercise WriteTypeBitMapsTo using DNS type values:
[16, 46, 47, 256]Expected: the serialised bitmap includes window 1, length 1, with the first bit set (01 01 80).
Potential impact
The resulting signed NSEC bitmap incorrectly claims that no URI RRset exists at an owner where URI records are present.
This could affect DNSSEC-validating resolvers, particularly where negative caching or aggressive use of NSEC proofs is enabled.
The observed DNS signatures are cryptographically valid for the incorrect wire representation, so ordinary signature verification alone does not detect the semantic inconsistency.
No specific validating-client outage has been demonstrated.
Questions
Can you confirm whether the
maxBits > 0window-presence condition is a defect affecting URI type 256 and other types at offset zero in nonzero bitmap windows?Is there an existing fix, planned release or recommended patch addressing this behaviour?
After upgrading to a corrected library, must existing NSEC records be regenerated and re-signed? What supported procedure would preserve existing DNSKEYs, positive RRsets and live dynamic DNS updates?
Is there a recommended method for confirming the precise TechnitiumLibrary DLL build used by a deployed DNS Server installation?
Separately, we have observed an NSEC
NextDomainNamepointing across a historical child-zone boundary to an incorrect successor. Is there a supported diagnostic or repair procedure for stale NSEC chain ordering? We do not assume this has the same root cause.
Additional notes
No manual NSEC or RRSIG editing, DNSSEC key rotation, restart, resync or signing-mode change was performed during this test.
Further production modifications have been stopped pending diagnosis.
I can provide additional sanitised authoritative responses, NSEC RDATA, signature verification results and implementation-path analysis if required.
SummaryTechnitium DNS Server 15.6.2 appears to contain an NSEC type-bitmap serialisation defect affecting DNS record type URI (256).
A DNSSEC-signed authoritative zone can serve an NSEC bitmap that incorrectly omits URI, despite URI records being present and correctly signed.
Following a normal Update Record operation, the primary's records API and textual zone export include URI in the NSEC type list, but authoritative UDP/TCP responses and secondary zone transfers continue to omit it.
Investigation of the release-matched TechnitiumLibrary source identified a likely off-by-one/window-presence defect in DnsNSECRecordData.WriteTypeBitMapsTo.
Suspected root cause
Source:
DnsNSECRecordData.cs — dns-server-v15.6.2
The method surveys each NSEC type-bitmap window using its highest bit offset:
if (windowBlockSurvey[windowBlockNumber] < bitNumber)
windowBlockSurvey[windowBlockNumber] = bitNumber;
It then only emits windows where:
if (maxBits > 0)
URI has DNS resource record type 256, corresponding to:
Window number: 1
Bit offset: 0
When URI is the only record type in window 1, the maximum bit offset remains zero. This is indistinguishable from an absent window under the current condition.
Consequently, the serializer can omit window 1 entirely.
The correct encoded bitmap window should contain:
01 01 80
The NSEC object also maintains a logical Types collection separate from the serialised _rData bytes.
This potentially explains why:
API and textual zone export display URI correctly.
DNSSEC signing processes serialised bytes without URI.
Authoritative DNS answers omit URI.
Zone transfers propagate the URI-omitting representation.
The release-matched source and the observed behaviour strongly support this explanation. However, the exact deployed TechnitiumLibrary DLL has not been independently verified as binary-equivalent to the reviewed source.
The same suspect source condition was also observed in the master branch during investigation.
Environment
Technitium DNS Server: 15.6.2
Two authoritative DNS servers configured as primary and secondary
DNSSEC signing: NSEC
Existing signed zone with dynamically maintained records
URI record sets containing four members
URI priority: 0
URI weight: 100
TTL: 3600
Production hostnames, addresses and credentials have been omitted.
Observed behaviour
At an internal owner equivalent to:
_kerberos.test.invalid.
The zone contains TXT and URI RRsets. Four URI records exist and resolve correctly.
The correct NSEC type bitmap is:
TXT RRSIG NSEC URI
Before maintenance, both authoritative servers instead returned:
TXT RRSIG NSEC
URI was incorrectly omitted.
Maintenance test
One documented POST /api/zones/records/update request was executed on the primary, reapplying an existing URI member with unchanged:
Owner name
URI target
Priority and weight
TTL
Enabled state
Expiry configuration
The API returned HTTP 200 and status: ok.
The zone SOA advanced monotonically. All four original URI records, positive DNS values, TTLs and DNSKEYs were preserved.
Results after the update
Source
NSEC type bitmap
Primary records API
TXT RRSIG NSEC URI
Primary textual zone export
TXT RRSIG NSEC URI
Primary authoritative UDP
TXT RRSIG NSEC
Primary authoritative TCP
TXT RRSIG NSEC
Secondary records API/export
TXT RRSIG NSEC
Secondary authoritative UDP/TCP
TXT RRSIG NSEC
The discrepancy persisted across repeated read-only checks.
Importantly:
The NSEC RRSIG successfully verifies against the URI-omitting authoritative wire representation.
The same signature fails verification against the primary's URI-inclusive text-export representation.
The URI RRset itself remains correctly signed and verifiable.
The secondary successfully refreshed and converged its SOA and current signatures, but retained the incorrect bitmap.
No additional authoritative wire-level fault or client outage was demonstrated.
The result suggests the NSEC object retains URI in its logical type collection while its serialised representation omits the corresponding bitmap window.
Suggested minimal reproduction
In an isolated test installation:
Create a DNSSEC-signed NSEC zone, such as test.invalid.
Create an owner _kerberos.test.invalid containing a TXT record and URI records.
Use URI type 256 as the only type in bitmap window 1.
Compare the records API and zone-file export against direct authoritative NSEC responses.
Update an existing URI record without changing its values using the documented Update Record API.
Repeat the comparison and verify the NSEC RRSIG against both representations.
Optionally transfer the zone to a secondary and inspect its resulting bitmap.
For a smaller unit test, exercise WriteTypeBitMapsTo using DNS type values:
[16, 46, 47, 256]
Expected: the serialised bitmap includes window 1, length 1, with the first bit set (01 01 80).
Potential impact
The resulting signed NSEC bitmap incorrectly claims that no URI RRset exists at an owner where URI records are present.
This could affect DNSSEC-validating resolvers, particularly where negative caching or aggressive use of NSEC proofs is enabled.
The observed DNS signatures are cryptographically valid for the incorrect wire representation, so ordinary signature verification alone does not detect the semantic inconsistency.
No specific validating-client outage has been demonstrated.
Questions
Can you confirm whether the maxBits > 0 window-presence condition is a defect affecting URI type 256 and other types at offset zero in nonzero bitmap windows?
Is there an existing fix, planned release or recommended patch addressing this behaviour?
After upgrading to a corrected library, must existing NSEC records be regenerated and re-signed? What supported procedure would preserve existing DNSKEYs, positive RRsets and live dynamic DNS updates?
Is there a recommended method for confirming the precise TechnitiumLibrary DLL build used by a deployed DNS Server installation?
Separately, we have observed an NSEC NextDomainName pointing across a historical child-zone boundary to an incorrect successor. Is there a supported diagnostic or repair procedure for stale NSEC chain ordering? We do not assume this has the same root cause.
Additional notes
No manual NSEC or RRSIG editing, DNSSEC key rotation, restart, resync or signing-mode change was performed during this test.
Further production modifications have been stopped pending diagnosis.
I can provide additional sanitised authoritative responses, NSEC RDATA, signature verification results and implementation-path analysis if required.
Activity
ShreyasZare commentedon Oct 21, 2026
Thanks for reporting this issue. I am able to reproduce this and have found a fix for it. Will get this fixed in the next update.