Skip to content

Bug: NSEC bitmap serializer omits URI record type 256, causing incorrect signed denial and API/wire mismatch #2244

Open

Description

@BKOmega

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: 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:

  1. The NSEC RRSIG successfully verifies against the URI-omitting authoritative wire representation.

  2. The same signature fails verification against the primary's URI-inclusive text-export representation.

  3. The URI RRset itself remains correctly signed and verifiable.

  4. The secondary successfully refreshed and converged its SOA and current signatures, but retained the incorrect bitmap.

  5. 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:

  1. Create a DNSSEC-signed NSEC zone, such as test.invalid.

  2. Create an owner _kerberos.test.invalid containing a TXT record and URI records.

  3. Use URI type 256 as the only type in bitmap window 1.

  4. Compare the records API and zone-file export against direct authoritative NSEC responses.

  5. Update an existing URI record without changing its values using the documented Update Record API.

  6. Repeat the comparison and verify the NSEC RRSIG against both representations.

  7. 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

  1. 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?

  2. Is there an existing fix, planned release or recommended patch addressing this behaviour?

  3. 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?

  4. Is there a recommended method for confirming the precise TechnitiumLibrary DLL build used by a deployed DNS Server installation?

  5. 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.

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: 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

  1. ShreyasZare commented on Oct 21, 2026

    @ShreyasZare
    Member

    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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions