CWE-807
AllowedReliance on Untrusted Inputs in a Security Decision
Abstraction: Base · Status: Incomplete
The product uses a protection mechanism that relies on the existence or values of an input, but the input can be modified by an untrusted actor in a way that bypasses the protection mechanism.
145 vulnerabilities reference this CWE, most recent first.
GHSA-WV46-V6XC-2QHF
Vulnerability from github – Published: 2026-03-26 19:08 – Updated: 2026-04-10 19:46Summary
Synology Chat reply delivery could rebind to a mutable username match instead of the stable numeric user_id recorded by the webhook event.
Affected Packages / Versions
- Package:
openclaw(npm) - Affected: < 2026.3.22
- Fixed: >= 2026.3.22
- Latest released tag checked:
v2026.3.23-2(630f1479c44f78484dfa21bb407cbe6f171dac87) - Latest published npm version checked:
2026.3.23-2
Fix Commit(s)
7ade3553b74ee3f461c4acd216653d5ba411f455
Release Status
The fix shipped in v2026.3.22 and remains present in v2026.3.23 and v2026.3.23-2.
Code-Level Confirmation
- extensions/synology-chat/src/webhook-handler.ts now keeps replies bound to the stable webhook user identifier unless an explicit dangerous opt-in is enabled.
- extensions/synology-chat/src/config-schema.ts contains the explicit dangerous opt-in seam instead of silent username rebinding.
OpenClaw thanks @nexrin for reporting.
{
"affected": [
{
"package": {
"ecosystem": "npm",
"name": "openclaw"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "2026.3.22"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2026-35670"
],
"database_specific": {
"cwe_ids": [
"CWE-639",
"CWE-706",
"CWE-807"
],
"github_reviewed": true,
"github_reviewed_at": "2026-03-26T19:08:16Z",
"nvd_published_at": "2026-04-10T17:17:09Z",
"severity": "MODERATE"
},
"details": "## Summary\nSynology Chat reply delivery could rebind to a mutable username match instead of the stable numeric user_id recorded by the webhook event.\n\n## Affected Packages / Versions\n- Package: `openclaw` (npm)\n- Affected: \u003c 2026.3.22\n- Fixed: \u003e= 2026.3.22\n- Latest released tag checked: `v2026.3.23-2` (`630f1479c44f78484dfa21bb407cbe6f171dac87`)\n- Latest published npm version checked: `2026.3.23-2`\n\n## Fix Commit(s)\n- `7ade3553b74ee3f461c4acd216653d5ba411f455`\n\n## Release Status\nThe fix shipped in `v2026.3.22` and remains present in `v2026.3.23` and `v2026.3.23-2`.\n\n## Code-Level Confirmation\n- extensions/synology-chat/src/webhook-handler.ts now keeps replies bound to the stable webhook user identifier unless an explicit dangerous opt-in is enabled.\n- extensions/synology-chat/src/config-schema.ts contains the explicit dangerous opt-in seam instead of silent username rebinding.\n\nOpenClaw thanks @nexrin for reporting.",
"id": "GHSA-wv46-v6xc-2qhf",
"modified": "2026-04-10T19:46:22Z",
"published": "2026-03-26T19:08:16Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/openclaw/openclaw/security/advisories/GHSA-wv46-v6xc-2qhf"
},
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-35670"
},
{
"type": "WEB",
"url": "https://github.com/openclaw/openclaw/commit/630f1479c44f78484dfa21bb407cbe6f171dac87"
},
{
"type": "WEB",
"url": "https://github.com/openclaw/openclaw/commit/7ade3553b74ee3f461c4acd216653d5ba411f455"
},
{
"type": "PACKAGE",
"url": "https://github.com/openclaw/openclaw"
},
{
"type": "WEB",
"url": "https://www.vulncheck.com/advisories/openclaw-webhook-reply-rebinding-via-username-resolution-in-synology-chat"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:U/C:H/I:L/A:N",
"type": "CVSS_V3"
},
{
"score": "CVSS:4.0/AV:N/AC:H/AT:N/PR:L/UI:N/VC:H/VI:L/VA:N/SC:N/SI:N/SA:N",
"type": "CVSS_V4"
}
],
"summary": "OpenClaw: Synology Chat reply delivery could be rebound through username-based user resolution."
}
GHSA-X845-2F78-7V36
Vulnerability from github – Published: 2026-06-19 20:47 – Updated: 2026-06-19 20:47Summary
Blocky accepts and caches forged DNS answers while dnssec.validate: true is enabled. The issue has two related exploit paths:
-
Basic DNSSEC validation bypass. If an untrusted upstream returns an unsigned positive answer for a DNSSEC-signed public domain, Blocky classifies the response as
Insecuresolely because the response contains no RRSIG records. It does not first check the DS/DNSKEY chain to determine whether the queried name is below a signed delegation. The forged unsigned answer is returned and cached. -
Validation-cache scope pollution through forged insecure proofs. If a response contains some RRSIG material and enters RRset validation, an attacker-controlled response path can still cause Blocky to cache
ValidationResultInsecurefor the bare domain name by returning a DS response with no DS records and an unsigned NSEC/NSEC3 record in the authority section. Blocky treats the mere presence of NSEC/NSEC3 as authenticated DS absence and stores the resultingInsecurestate without validating the parent-zone proof. That cached state is keyed only by domain name and can be reused for later responses and cache hits.
Both paths were reproduced through Blocky's real DNS listener using external UDP DNS client queries. In both reproductions, the malicious upstream was shut down before the second query; Blocky still returned the poisoned answer from its own cache.
DNSSEC validation Configuration
The PoCs use Blocky's documented DNSSEC configuration model. This is not a misconfiguration.
Blocky's own documentation states that the basic DNSSEC configuration is:
dnssec:
validate: true
The documentation says this enables DNSSEC validation with default settings and built-in root trust anchors, and that Blocky will validate DNSSEC-signed domains. It also states that, when DNSSEC validation is enabled, Blocky will:
- set the DNSSEC OK bit on upstream queries;
- validate RRSIG records;
- verify the chain of trust from the root zone to the queried domain using DNSKEY and DS records;
- return SERVFAIL for bogus signatures;
- protect against cache poisoning, man-in-the-middle attacks, DNS spoofing, and forged denial-of-existence.
The implementation-side defaults match this documented usage:
config/dnssec.godefinesDNSSEC.Validateas thednssec.validateoption.config/dnssec.godocumentsTrustAnchors []stringas custom trust anchors; an empty value uses built-in IANA root trust anchors.- The PoCs set
cfg.DNSSEC.Validate = trueand do not overrideTrustAnchors, so they use the documented built-in root trust-anchor path. - The PoCs use
config.NetProtocolTcpUdpas the upstream transport, which is one of the documented upstream protocols. - The cache configuration is normal Blocky behavior:
caching.maxTime >= 0enables caching, and the PoCs set a positivemaxTimeonly to make cache replay observable.
Therefore, the expected behavior for a signed public domain such as cloudflare.com. is not to accept an unsigned forged answer. A validating resolver must determine whether the name is covered by a signed delegation before treating missing signatures as Insecure.
Threat models and attack paths
Attack model 1: untrusted recursive upstream or upstream-path attacker
This is the direct DNSSEC threat model. DNSSEC validation is supposed to protect clients even when the recursive upstream response path is malicious, compromised, or tampered with.
The attacker can be:
- a malicious recursive upstream configured in Blocky;
- an attacker who can tamper with plaintext UDP/TCP DNS traffic between Blocky and its upstream;
- a compromised upstream resolver;
- a misrouted or attacker-controlled conditional upstream.
Attack steps:
- The client queries Blocky for a DNSSEC-signed public name, for example
cloudflare.com. A. - The attacker-controlled upstream returns an unsigned forged positive answer, for example
cloudflare.com. 120 IN A 203.0.113.77. - Blocky observes that the response contains no RRSIG records.
- Blocky returns
ValidationResultInsecurewithout issuing target DS or DNSKEY queries. - The forged answer is returned to the client and cached.
- Later clients receive the cached forged answer, even if the malicious upstream is no longer reachable.
This path is demonstrated by attachments/external-dnssec-basic-bypass/main.go.
Attack model 2: forged insecure proof / validation-cache scope pollution
This path exercises the validator's insecure-proof and cache-scope logic. It is relevant when the response enters RRset validation and when different DNS views or response paths can seed DNSSEC state for the same domain name.
The attacker can be:
- an attacker-controlled recursive upstream;
- a network attacker who can tamper with DS/DNSKEY auxiliary queries;
- a conditional-forwarding or split-horizon configuration that causes the final answer and DNSSEC auxiliary lookups to come from different views;
- a malicious upstream group selected for DNSSEC auxiliary queries but not necessarily for the original user-facing answer.
Attack steps:
- The client queries Blocky for
victim.signed.example. A. - The attacker returns a poisoned A RR and an unrelated decoy RRSIG. The A RRset itself has no matching RRSIG, but the response contains some RRSIG material, so Blocky enters RRset validation instead of the simple
no RRSIGbranch. - Blocky attempts to determine whether
victim.signed.example.is in a signed or unsigned zone by querying DS records. - The attacker returns a DS response with no DS records and an unsigned NSEC record in the authority section.
- Blocky treats the mere presence of NSEC as authenticated DS absence, caches
ValidationResultInsecurefor the bare domain name, and accepts the unsigned A RRset. - The poisoned answer is returned and cached.
- On later queries, Blocky reuses both the poisoned DNS response cache entry and the polluted validation status. The PoC confirms replay after the malicious upstream is shut down.
This path is demonstrated by attachments/external-dnssec-cache-scope-pollution/main.go.
Details
1. no RRSIG is treated as Insecure before chain status is checked
In resolver/dnssec/validator.go, ValidateResponse dispatches as follows:
switch {
case !v.hasAnySignatures(response):
v.logger.Debugf("No RRSIG records found for %s - zone is unsigned", question.Name)
result = ValidationResultInsecure
case len(response.Answer) > 0:
result = v.validateAnswer(ctx, response, question)
...
}
The bug is the assumption that a response with no RRSIG records means the zone is unsigned. That assumption is not valid for a validating resolver. The resolver must first prove that the queried name is below an insecure delegation. For a signed domain, an unsigned positive answer should be Bogus, not Insecure.
The basic bypass PoC uses cloudflare.com., a public DNSSEC-signed domain. Blocky returns NOERROR and the forged A record while issuing zero target DS and DNSKEY queries.
2. Cache writes happen before outer DNSSEC validation can reject or transform the response
server/server.go:526-543 constructs the resolver chain with dnssecResolver before cachingResolver and includes a comment saying DNSSEC validation happens before caching:
dnssecResolver, // DNSSEC validation BEFORE caching - validates all responses before they are cached
cachingResolver,
...
upstreamTree,
However, chained resolver execution is outer-to-inner. DNSSECResolver.Resolve first calls r.next.Resolve, and CachingResolver.Resolve writes cache entries on misses before control returns to the DNSSEC layer:
resolver/dnssec_resolver.go:88-96: the DNSSEC resolver callsr.next.Resolve(ctx, request)beforeValidateResponse.resolver/caching_resolver.go:225-230: on cache miss, the cache resolver calls the next resolver and then immediately callsputInCache.resolver/caching_resolver.go:326-341: the cache write only checks rcode and basic cacheability; it does not bind the entry to a DNSSEC validation result.
The practical result is that the DNS response cache can store data that has not yet survived final DNSSEC validation.
3. Validation cache is keyed only by bare domain name
resolver/dnssec/chain.go:16-31 exposes:
getCachedValidation(domain string)
setCachedValidation(domain string, result ValidationResult)
resolver/dnssec/validator.go:638-642 reuses this cache for zone-security checks:
if cached, found := v.getCachedValidation(domain); found {
return cached
}
The key does not include:
- qclass;
- qtype or proof purpose;
- current client view;
- ECS, client IP, client name, or request client ID;
- conditional-forwarding branch;
- effective upstream group;
- proof source zone;
- parent zone;
- trust-anchor path;
- validation policy or algorithm set.
This allows one response path or proof purpose to seed a DNSSEC status for another path.
4. Unsigned NSEC/NSEC3 presence is treated as authenticated DS absence
resolver/dnssec/validator.go:655-667 queries DS records when an RRset has no matching RRSIG. If no DS records are extracted, it calls handleNoDSRecords.
resolver/dnssec/validator.go:682-690 then does:
hasNSEC := len(extractNSECRecords(dsResponse.Ns)) > 0
hasNSEC3 := len(extractNSEC3Records(dsResponse.Ns)) > 0
if hasNSEC || hasNSEC3 {
result := ValidationResultInsecure
v.setCachedValidation(domain, result)
return result
}
This code does not validate the NSEC/NSEC3 RRset signature and does not validate the parent zone chain before trusting the denial proof. The comment calls this an authenticated denial of DS existence, but the code only checks for record presence.
5. DNSSEC auxiliary queries do not preserve original request context
resolver/dnssec_resolver.go:47-52 creates the validator with upstream as the resolver used for DS/DNSKEY lookups. resolver/dnssec/query.go:57-69 builds synthetic requests containing only qname/qtype and sends them to v.upstream.Resolve.
Those synthetic requests do not preserve the original request's client IP, client names, ECS data, request client ID, or conditional-forwarding context. resolver/upstream_tree_resolver.go:123-162 chooses upstream groups based on client metadata; missing metadata can cause DNSSEC auxiliary queries to use a different upstream view from the answer being validated.
This is a scope problem even apart from the direct basic bypass.
Reproduction
Environment
- Repository:
/home/hurrison/workspace/dnssec/repos/blocky - Commit:
e0ea9b3ea56e3d074569abd3010251e7c6ebd593 - No root privileges required.
- No public DNS dependency; PoCs use local loopback high ports.
- Both PoCs query Blocky's real DNS listener through UDP.
PoC 1: basic unsigned-response DNSSEC bypass
Run:
cd /home/hurrison/workspace/dnssec/repos/blocky
go run ./exp/external-dnssec-basic-bypass
Artifact:
report/artifacts/basic-bypass-output.txt
Key output:
query 1:
rcode: NOERROR
answers: cloudflare.com. A 203.0.113.77 ttl=120
target A upstream queries: 1
target DS upstream queries: 0
target DNSKEY upstream queries: 0
stopping malicious upstream before query 2
query 2:
rcode: NOERROR
answers: cloudflare.com. A 203.0.113.77 ttl=120
target A upstream queries: 1
target DS upstream queries: 0
target DNSKEY upstream queries: 0
BASIC BYPASS CONFIRMED: Blocky accepted and cached an unsigned poisoned response without querying DS/DNSKEY for the target.
Interpretation:
cloudflare.com.is treated as if it were insecure only because the forged response contained no RRSIG records.- Blocky does not query DS or DNSKEY for the target before accepting the answer.
- The second answer is served after the malicious upstream is shut down, proving cache replay.
PoC 2: forged insecure proof and validation-cache scope pollution
Run:
cd /home/hurrison/workspace/dnssec/repos/blocky
go run ./exp/external-dnssec-cache-scope-pollution
Artifact:
report/artifacts/poc-output.txt
Key output:
query 1:
rcode: NOERROR
answers: victim.signed.example. A 203.0.113.66 ttl=120 | decoy.victim.signed.example. RRSIG type-covered=TXT ttl=120
victim A upstream queries: 1
victim DS proof queries: 1
stopping malicious upstream before query 2
query 2:
rcode: NOERROR
answers: victim.signed.example. A 203.0.113.66 ttl=119 | decoy.victim.signed.example. RRSIG type-covered=TXT ttl=119
victim A upstream queries: 1
victim DS proof queries: 1
EXP SUCCESS: poisoned data was accepted over Blocky's DNS listener and replayed on a second external query after the malicious upstream was shut down.
Interpretation:
- The response contains an unrelated RRSIG to force the RRset-validation path.
- The A RRset has no matching RRSIG.
- The forged DS response contains no DS and an unsigned NSEC in authority.
- Blocky caches
Insecurefor the domain and returns the poisoned answer. - The second response is served after the malicious upstream is shut down.
Expected behavior
For a DNSSEC validating resolver:
- Missing RRSIGs in a positive response must not automatically imply an insecure zone.
- The resolver must prove that the queried name is under an insecure delegation before accepting an unsigned answer.
- If the parent chain indicates the name should be signed, an unsigned positive answer must be treated as bogus.
- DS absence must be proven by authenticated denial of existence, not by the mere presence of NSEC/NSEC3 records.
- DNS response cache entries must not be written before the final DNSSEC decision, or they must be bound to validation metadata that is checked on cache hit.
- Validation cache entries must be scoped to the proof purpose, class, view, upstream group, proof source, and trust path.
Actual behavior
- Unsigned positive responses are classified as
Insecurewithout DS/DNSKEY chain checks. CachingResolverwrites responses before outer DNSSEC validation runs.- An unsigned NSEC/NSEC3 in a DS response can mark a domain as
Insecure. - The
Insecureresult is cached by bare domain name. - Poisoned answers are replayed from Blocky's DNS cache on later external queries.
Impact
The impact is DNSSEC validation bypass and persistent DNS cache poisoning:
- forged A/AAAA/CNAME/MX/TXT records can be returned for signed domains;
- poisoned records can be replayed to later clients for the cache TTL;
- traffic can be redirected to attacker-controlled infrastructure;
- update systems, package mirrors, service discovery, mail routing, and TLS bootstrapping flows may be affected depending on client behavior;
- split-horizon and conditional-forwarding deployments may suffer cross-view validation-state pollution;
- an attacker can also induce false
BogusorIndeterminatestates in related logic, causing targeted SERVFAIL or AD-bit stripping.
The basic bypass is sufficient for a malicious or intercepted recursive upstream to defeat Blocky's documented DNSSEC protection. The cache-scope pollution path shows additional design risk in deployments with multiple views, upstream groups, or conditional forwarding.
Attachments
blocky-dnssec-validation-cache-scope-pollution-attachments.zip
report/
blocky-dnssec-validation-cache-scope-pollution-report.md
attachments/
external-dnssec-basic-bypass/
main.go
README.md
external-dnssec-cache-scope-pollution/
main.go
README.md
artifacts/
basic-bypass-output.txt
poc-output.txt
Attachment descriptions:
attachments/external-dnssec-basic-bypass/main.go: external PoC for the direct unsigned-response DNSSEC bypass.attachments/external-dnssec-basic-bypass/README.md: usage notes for the basic bypass PoC.attachments/external-dnssec-cache-scope-pollution/main.go: external PoC for forged insecure proof and validation-cache scope pollution.attachments/external-dnssec-cache-scope-pollution/README.md: usage notes for the cache-scope PoC.artifacts/basic-bypass-output.txt: recorded output for PoC 1.artifacts/poc-output.txt: recorded output for PoC 2.
Credit
Yuheng Zhang @ Tsinghua University Jianjun Chen@ Tsinghua University
{
"affected": [
{
"package": {
"ecosystem": "Go",
"name": "github.com/0xERR0R/blocky"
},
"ranges": [
{
"events": [
{
"introduced": "0.28.0"
},
{
"fixed": "0.32.0"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [],
"database_specific": {
"cwe_ids": [
"CWE-346",
"CWE-807"
],
"github_reviewed": true,
"github_reviewed_at": "2026-06-19T20:47:46Z",
"nvd_published_at": null,
"severity": "HIGH"
},
"details": "## Summary\n\nBlocky accepts and caches forged DNS answers while `dnssec.validate: true` is enabled. The issue has two related exploit paths:\n\n1. **Basic DNSSEC validation bypass.** If an untrusted upstream returns an unsigned positive answer for a DNSSEC-signed public domain, Blocky classifies the response as `Insecure` solely because the response contains no RRSIG records. It does not first check the DS/DNSKEY chain to determine whether the queried name is below a signed delegation. The forged unsigned answer is returned and cached.\n\n2. **Validation-cache scope pollution through forged insecure proofs.** If a response contains some RRSIG material and enters RRset validation, an attacker-controlled response path can still cause Blocky to cache `ValidationResultInsecure` for the bare domain name by returning a DS response with no DS records and an unsigned NSEC/NSEC3 record in the authority section. Blocky treats the mere presence of NSEC/NSEC3 as authenticated DS absence and stores the resulting `Insecure` state without validating the parent-zone proof. That cached state is keyed only by domain name and can be reused for later responses and cache hits.\n\nBoth paths were reproduced through Blocky\u0027s real DNS listener using external UDP DNS client queries. In both reproductions, the malicious upstream was shut down before the second query; Blocky still returned the poisoned answer from its own cache.\n\n\n## DNSSEC validation Configuration\n\nThe PoCs use Blocky\u0027s documented DNSSEC configuration model. This is not a misconfiguration.\n\nBlocky\u0027s own documentation states that the basic DNSSEC configuration is:\n\n```yaml\ndnssec:\n validate: true\n```\n\nThe documentation says this enables DNSSEC validation with default settings and built-in root trust anchors, and that Blocky will validate DNSSEC-signed domains. It also states that, when DNSSEC validation is enabled, Blocky will:\n\n- set the DNSSEC OK bit on upstream queries;\n- validate RRSIG records;\n- verify the chain of trust from the root zone to the queried domain using DNSKEY and DS records;\n- return SERVFAIL for bogus signatures;\n- protect against cache poisoning, man-in-the-middle attacks, DNS spoofing, and forged denial-of-existence.\n\nThe implementation-side defaults match this documented usage:\n\n- `config/dnssec.go` defines `DNSSEC.Validate` as the `dnssec.validate` option.\n- `config/dnssec.go` documents `TrustAnchors []string` as custom trust anchors; an empty value uses built-in IANA root trust anchors.\n- The PoCs set `cfg.DNSSEC.Validate = true` and do not override `TrustAnchors`, so they use the documented built-in root trust-anchor path.\n- The PoCs use `config.NetProtocolTcpUdp` as the upstream transport, which is one of the documented upstream protocols.\n- The cache configuration is normal Blocky behavior: `caching.maxTime \u003e= 0` enables caching, and the PoCs set a positive `maxTime` only to make cache replay observable.\n\nTherefore, the expected behavior for a signed public domain such as `cloudflare.com.` is not to accept an unsigned forged answer. A validating resolver must determine whether the name is covered by a signed delegation before treating missing signatures as `Insecure`.\n\n## Threat models and attack paths\n\n### Attack model 1: untrusted recursive upstream or upstream-path attacker\n\nThis is the direct DNSSEC threat model. DNSSEC validation is supposed to protect clients even when the recursive upstream response path is malicious, compromised, or tampered with.\n\nThe attacker can be:\n\n- a malicious recursive upstream configured in Blocky;\n- an attacker who can tamper with plaintext UDP/TCP DNS traffic between Blocky and its upstream;\n- a compromised upstream resolver;\n- a misrouted or attacker-controlled conditional upstream.\n\nAttack steps:\n\n1. The client queries Blocky for a DNSSEC-signed public name, for example `cloudflare.com. A`.\n2. The attacker-controlled upstream returns an unsigned forged positive answer, for example `cloudflare.com. 120 IN A 203.0.113.77`.\n3. Blocky observes that the response contains no RRSIG records.\n4. Blocky returns `ValidationResultInsecure` without issuing target DS or DNSKEY queries.\n5. The forged answer is returned to the client and cached.\n6. Later clients receive the cached forged answer, even if the malicious upstream is no longer reachable.\n\nThis path is demonstrated by `attachments/external-dnssec-basic-bypass/main.go`.\n\n### Attack model 2: forged insecure proof / validation-cache scope pollution\n\nThis path exercises the validator\u0027s insecure-proof and cache-scope logic. It is relevant when the response enters RRset validation and when different DNS views or response paths can seed DNSSEC state for the same domain name.\n\nThe attacker can be:\n\n- an attacker-controlled recursive upstream;\n- a network attacker who can tamper with DS/DNSKEY auxiliary queries;\n- a conditional-forwarding or split-horizon configuration that causes the final answer and DNSSEC auxiliary lookups to come from different views;\n- a malicious upstream group selected for DNSSEC auxiliary queries but not necessarily for the original user-facing answer.\n\nAttack steps:\n\n1. The client queries Blocky for `victim.signed.example. A`.\n2. The attacker returns a poisoned A RR and an unrelated decoy RRSIG. The A RRset itself has no matching RRSIG, but the response contains some RRSIG material, so Blocky enters RRset validation instead of the simple `no RRSIG` branch.\n3. Blocky attempts to determine whether `victim.signed.example.` is in a signed or unsigned zone by querying DS records.\n4. The attacker returns a DS response with no DS records and an unsigned NSEC record in the authority section.\n5. Blocky treats the mere presence of NSEC as authenticated DS absence, caches `ValidationResultInsecure` for the bare domain name, and accepts the unsigned A RRset.\n6. The poisoned answer is returned and cached.\n7. On later queries, Blocky reuses both the poisoned DNS response cache entry and the polluted validation status. The PoC confirms replay after the malicious upstream is shut down.\n\nThis path is demonstrated by `attachments/external-dnssec-cache-scope-pollution/main.go`.\n\n## Details\n\n### 1. `no RRSIG` is treated as `Insecure` before chain status is checked\n\nIn `resolver/dnssec/validator.go`, `ValidateResponse` dispatches as follows:\n\n```go\nswitch {\ncase !v.hasAnySignatures(response):\n v.logger.Debugf(\"No RRSIG records found for %s - zone is unsigned\", question.Name)\n result = ValidationResultInsecure\ncase len(response.Answer) \u003e 0:\n result = v.validateAnswer(ctx, response, question)\n...\n}\n```\n\nThe bug is the assumption that a response with no RRSIG records means the zone is unsigned. That assumption is not valid for a validating resolver. The resolver must first prove that the queried name is below an insecure delegation. For a signed domain, an unsigned positive answer should be `Bogus`, not `Insecure`.\n\nThe basic bypass PoC uses `cloudflare.com.`, a public DNSSEC-signed domain. Blocky returns `NOERROR` and the forged A record while issuing zero target DS and DNSKEY queries.\n\n### 2. Cache writes happen before outer DNSSEC validation can reject or transform the response\n\n`server/server.go:526-543` constructs the resolver chain with `dnssecResolver` before `cachingResolver` and includes a comment saying DNSSEC validation happens before caching:\n\n```text\ndnssecResolver, // DNSSEC validation BEFORE caching - validates all responses before they are cached\ncachingResolver,\n...\nupstreamTree,\n```\n\nHowever, chained resolver execution is outer-to-inner. `DNSSECResolver.Resolve` first calls `r.next.Resolve`, and `CachingResolver.Resolve` writes cache entries on misses before control returns to the DNSSEC layer:\n\n- `resolver/dnssec_resolver.go:88-96`: the DNSSEC resolver calls `r.next.Resolve(ctx, request)` before `ValidateResponse`.\n- `resolver/caching_resolver.go:225-230`: on cache miss, the cache resolver calls the next resolver and then immediately calls `putInCache`.\n- `resolver/caching_resolver.go:326-341`: the cache write only checks rcode and basic cacheability; it does not bind the entry to a DNSSEC validation result.\n\nThe practical result is that the DNS response cache can store data that has not yet survived final DNSSEC validation.\n\n### 3. Validation cache is keyed only by bare domain name\n\n`resolver/dnssec/chain.go:16-31` exposes:\n\n```go\ngetCachedValidation(domain string)\nsetCachedValidation(domain string, result ValidationResult)\n```\n\n`resolver/dnssec/validator.go:638-642` reuses this cache for zone-security checks:\n\n```go\nif cached, found := v.getCachedValidation(domain); found {\n return cached\n}\n```\n\nThe key does not include:\n\n- qclass;\n- qtype or proof purpose;\n- current client view;\n- ECS, client IP, client name, or request client ID;\n- conditional-forwarding branch;\n- effective upstream group;\n- proof source zone;\n- parent zone;\n- trust-anchor path;\n- validation policy or algorithm set.\n\nThis allows one response path or proof purpose to seed a DNSSEC status for another path.\n\n### 4. Unsigned NSEC/NSEC3 presence is treated as authenticated DS absence\n\n`resolver/dnssec/validator.go:655-667` queries DS records when an RRset has no matching RRSIG. If no DS records are extracted, it calls `handleNoDSRecords`.\n\n`resolver/dnssec/validator.go:682-690` then does:\n\n```go\nhasNSEC := len(extractNSECRecords(dsResponse.Ns)) \u003e 0\nhasNSEC3 := len(extractNSEC3Records(dsResponse.Ns)) \u003e 0\n\nif hasNSEC || hasNSEC3 {\n result := ValidationResultInsecure\n v.setCachedValidation(domain, result)\n return result\n}\n```\n\nThis code does not validate the NSEC/NSEC3 RRset signature and does not validate the parent zone chain before trusting the denial proof. The comment calls this an authenticated denial of DS existence, but the code only checks for record presence.\n\n### 5. DNSSEC auxiliary queries do not preserve original request context\n\n`resolver/dnssec_resolver.go:47-52` creates the validator with `upstream` as the resolver used for DS/DNSKEY lookups. `resolver/dnssec/query.go:57-69` builds synthetic requests containing only qname/qtype and sends them to `v.upstream.Resolve`.\n\nThose synthetic requests do not preserve the original request\u0027s client IP, client names, ECS data, request client ID, or conditional-forwarding context. `resolver/upstream_tree_resolver.go:123-162` chooses upstream groups based on client metadata; missing metadata can cause DNSSEC auxiliary queries to use a different upstream view from the answer being validated.\n\nThis is a scope problem even apart from the direct basic bypass.\n\n## Reproduction\n\n### Environment\n\n- Repository: `/home/hurrison/workspace/dnssec/repos/blocky`\n- Commit: `e0ea9b3ea56e3d074569abd3010251e7c6ebd593`\n- No root privileges required.\n- No public DNS dependency; PoCs use local loopback high ports.\n- Both PoCs query Blocky\u0027s real DNS listener through UDP.\n\n### PoC 1: basic unsigned-response DNSSEC bypass\n\nRun:\n\n```sh\ncd /home/hurrison/workspace/dnssec/repos/blocky\ngo run ./exp/external-dnssec-basic-bypass\n```\n\nArtifact:\n\n```text\nreport/artifacts/basic-bypass-output.txt\n```\n\nKey output:\n\n```text\nquery 1:\n rcode: NOERROR\n answers: cloudflare.com. A 203.0.113.77 ttl=120\n target A upstream queries: 1\n target DS upstream queries: 0\n target DNSKEY upstream queries: 0\n\nstopping malicious upstream before query 2\nquery 2:\n rcode: NOERROR\n answers: cloudflare.com. A 203.0.113.77 ttl=120\n target A upstream queries: 1\n target DS upstream queries: 0\n target DNSKEY upstream queries: 0\n\nBASIC BYPASS CONFIRMED: Blocky accepted and cached an unsigned poisoned response without querying DS/DNSKEY for the target.\n```\n\nInterpretation:\n\n- `cloudflare.com.` is treated as if it were insecure only because the forged response contained no RRSIG records.\n- Blocky does not query DS or DNSKEY for the target before accepting the answer.\n- The second answer is served after the malicious upstream is shut down, proving cache replay.\n\n### PoC 2: forged insecure proof and validation-cache scope pollution\n\nRun:\n\n```sh\ncd /home/hurrison/workspace/dnssec/repos/blocky\ngo run ./exp/external-dnssec-cache-scope-pollution\n```\n\nArtifact:\n\n```text\nreport/artifacts/poc-output.txt\n```\n\nKey output:\n\n```text\nquery 1:\n rcode: NOERROR\n answers: victim.signed.example. A 203.0.113.66 ttl=120 | decoy.victim.signed.example. RRSIG type-covered=TXT ttl=120\n victim A upstream queries: 1\n victim DS proof queries: 1\n\nstopping malicious upstream before query 2\nquery 2:\n rcode: NOERROR\n answers: victim.signed.example. A 203.0.113.66 ttl=119 | decoy.victim.signed.example. RRSIG type-covered=TXT ttl=119\n victim A upstream queries: 1\n victim DS proof queries: 1\n\nEXP SUCCESS: poisoned data was accepted over Blocky\u0027s DNS listener and replayed on a second external query after the malicious upstream was shut down.\n```\n\nInterpretation:\n\n- The response contains an unrelated RRSIG to force the RRset-validation path.\n- The A RRset has no matching RRSIG.\n- The forged DS response contains no DS and an unsigned NSEC in authority.\n- Blocky caches `Insecure` for the domain and returns the poisoned answer.\n- The second response is served after the malicious upstream is shut down.\n\n## Expected behavior\n\nFor a DNSSEC validating resolver:\n\n- Missing RRSIGs in a positive response must not automatically imply an insecure zone.\n- The resolver must prove that the queried name is under an insecure delegation before accepting an unsigned answer.\n- If the parent chain indicates the name should be signed, an unsigned positive answer must be treated as bogus.\n- DS absence must be proven by authenticated denial of existence, not by the mere presence of NSEC/NSEC3 records.\n- DNS response cache entries must not be written before the final DNSSEC decision, or they must be bound to validation metadata that is checked on cache hit.\n- Validation cache entries must be scoped to the proof purpose, class, view, upstream group, proof source, and trust path.\n\n## Actual behavior\n\n- Unsigned positive responses are classified as `Insecure` without DS/DNSKEY chain checks.\n- `CachingResolver` writes responses before outer DNSSEC validation runs.\n- An unsigned NSEC/NSEC3 in a DS response can mark a domain as `Insecure`.\n- The `Insecure` result is cached by bare domain name.\n- Poisoned answers are replayed from Blocky\u0027s DNS cache on later external queries.\n\n## Impact\n\nThe impact is DNSSEC validation bypass and persistent DNS cache poisoning:\n\n- forged A/AAAA/CNAME/MX/TXT records can be returned for signed domains;\n- poisoned records can be replayed to later clients for the cache TTL;\n- traffic can be redirected to attacker-controlled infrastructure;\n- update systems, package mirrors, service discovery, mail routing, and TLS bootstrapping flows may be affected depending on client behavior;\n- split-horizon and conditional-forwarding deployments may suffer cross-view validation-state pollution;\n- an attacker can also induce false `Bogus` or `Indeterminate` states in related logic, causing targeted SERVFAIL or AD-bit stripping.\n\nThe basic bypass is sufficient for a malicious or intercepted recursive upstream to defeat Blocky\u0027s documented DNSSEC protection. The cache-scope pollution path shows additional design risk in deployments with multiple views, upstream groups, or conditional forwarding.\n\n## Attachments\n\n[blocky-dnssec-validation-cache-scope-pollution-attachments.zip](https://github.com/user-attachments/files/28940249/blocky-dnssec-validation-cache-scope-pollution-attachments.zip)\n\n```text\nreport/\n blocky-dnssec-validation-cache-scope-pollution-report.md\n attachments/\n external-dnssec-basic-bypass/\n main.go\n README.md\n external-dnssec-cache-scope-pollution/\n main.go\n README.md\n artifacts/\n basic-bypass-output.txt\n poc-output.txt\n```\n\nAttachment descriptions:\n\n- `attachments/external-dnssec-basic-bypass/main.go`: external PoC for the direct unsigned-response DNSSEC bypass.\n- `attachments/external-dnssec-basic-bypass/README.md`: usage notes for the basic bypass PoC.\n- `attachments/external-dnssec-cache-scope-pollution/main.go`: external PoC for forged insecure proof and validation-cache scope pollution.\n- `attachments/external-dnssec-cache-scope-pollution/README.md`: usage notes for the cache-scope PoC.\n- `artifacts/basic-bypass-output.txt`: recorded output for PoC 1.\n- `artifacts/poc-output.txt`: recorded output for PoC 2.\n\n## Credit\n\n[Yuheng Zhang @ Tsinghua University](mailto:zhangyuh25@mails.tsinghua.edu.cn)\n[Jianjun Chen@ Tsinghua University](mailto:jianjun@tsinghua.edu.cn)",
"id": "GHSA-x845-2f78-7v36",
"modified": "2026-06-19T20:47:46Z",
"published": "2026-06-19T20:47:46Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/0xERR0R/blocky/security/advisories/GHSA-x845-2f78-7v36"
},
{
"type": "PACKAGE",
"url": "https://github.com/0xERR0R/blocky"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:H/A:L",
"type": "CVSS_V3"
}
],
"summary": "Blocky DNSSEC validation bypass and validation-cache scope pollution"
}
GHSA-XH9J-MPC9-2M9P
Vulnerability from github – Published: 2026-03-21 03:31 – Updated: 2026-03-24 19:06Duplicate Advisory
This advisory has been withdrawn because it is a duplicate of GHSA-vvgp-4c28-m3jm. This link is maintained to preserve external references.
Original Description
OpenClaw versions prior to 2026.2.25 contain an authentication bypass vulnerability in the trusted-proxy Control UI pairing mechanism that accepts client.id=control-ui without proper device identity verification. An authenticated node role websocket client can exploit this by using the control-ui client identifier to skip pairing requirements and gain unauthorized access to node event execution flows.
{
"affected": [
{
"package": {
"ecosystem": "npm",
"name": "openclaw"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"last_affected": "2026.2.24"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [],
"database_specific": {
"cwe_ids": [
"CWE-807"
],
"github_reviewed": true,
"github_reviewed_at": "2026-03-24T19:06:15Z",
"nvd_published_at": "2026-03-21T01:17:09Z",
"severity": "MODERATE"
},
"details": "## Duplicate Advisory\n\nThis advisory has been withdrawn because it is a duplicate of GHSA-vvgp-4c28-m3jm. This link is maintained to preserve external references.\n\n## Original Description\nOpenClaw versions prior to 2026.2.25 contain an authentication bypass vulnerability in the trusted-proxy Control UI pairing mechanism that accepts client.id=control-ui without proper device identity verification. An authenticated node role websocket client can exploit this by using the control-ui client identifier to skip pairing requirements and gain unauthorized access to node event execution flows.",
"id": "GHSA-xh9j-mpc9-2m9p",
"modified": "2026-03-24T19:06:15Z",
"published": "2026-03-21T03:31:14Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/openclaw/openclaw/security/advisories/GHSA-vvgp-4c28-m3jm"
},
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-32057"
},
{
"type": "WEB",
"url": "https://github.com/openclaw/openclaw/commit/ec45c317f5d0631a3d333b236da58c4749ede2a3"
},
{
"type": "WEB",
"url": "https://www.vulncheck.com/advisories/openclaw-authentication-bypass-via-control-ui-client-id-parameter"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:U/C:L/I:H/A:N",
"type": "CVSS_V3"
},
{
"score": "CVSS:4.0/AV:N/AC:L/AT:P/PR:L/UI:N/VC:L/VI:H/VA:N/SC:N/SI:N/SA:N/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X",
"type": "CVSS_V4"
}
],
"summary": "Duplicate Advisory: OpenClaw has a Trusted-proxy Control UI pairing bypass which allows unpaired node sessions",
"withdrawn": "2026-03-24T19:06:15Z"
}
GHSA-XHQ5-45PM-2GJR
Vulnerability from github – Published: 2026-03-26 21:34 – Updated: 2026-04-18 00:56Summary
Nextcloud Talk room authorization matched on collidable room names instead of the stable room token, allowing policy confusion across similarly named rooms.
Affected Packages / Versions
- Package:
openclaw(npm) - Affected: < 2026.3.22
- Fixed: >= 2026.3.22
- Latest released tag checked:
v2026.3.23-2(630f1479c44f78484dfa21bb407cbe6f171dac87) - Latest published npm version checked:
2026.3.23-2
Fix Commit(s)
a47722de7e3c9cbda8d5512747ca7e3bb8f6ee66
Release Status
The fix shipped in v2026.3.22 and remains present in v2026.3.23 and v2026.3.23-2.
Code-Level Confirmation
- extensions/nextcloud-talk/src/inbound.ts now resolves allowlist policy from roomToken-backed room identity.
- extensions/nextcloud-talk/src/policy.ts now keys room authorization on stable room tokens instead of display names.
OpenClaw thanks @zpbrent for reporting.
{
"affected": [
{
"package": {
"ecosystem": "npm",
"name": "openclaw"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "2026.3.22"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2026-35624"
],
"database_specific": {
"cwe_ids": [
"CWE-639",
"CWE-807",
"CWE-863"
],
"github_reviewed": true,
"github_reviewed_at": "2026-03-26T21:34:18Z",
"nvd_published_at": null,
"severity": "LOW"
},
"details": "## Summary\nNextcloud Talk room authorization matched on collidable room names instead of the stable room token, allowing policy confusion across similarly named rooms.\n\n## Affected Packages / Versions\n- Package: `openclaw` (npm)\n- Affected: \u003c 2026.3.22\n- Fixed: \u003e= 2026.3.22\n- Latest released tag checked: `v2026.3.23-2` (`630f1479c44f78484dfa21bb407cbe6f171dac87`)\n- Latest published npm version checked: `2026.3.23-2`\n\n## Fix Commit(s)\n- `a47722de7e3c9cbda8d5512747ca7e3bb8f6ee66`\n\n## Release Status\nThe fix shipped in `v2026.3.22` and remains present in `v2026.3.23` and `v2026.3.23-2`.\n\n## Code-Level Confirmation\n- extensions/nextcloud-talk/src/inbound.ts now resolves allowlist policy from roomToken-backed room identity.\n- extensions/nextcloud-talk/src/policy.ts now keys room authorization on stable room tokens instead of display names.\n\nOpenClaw thanks @zpbrent for reporting.",
"id": "GHSA-xhq5-45pm-2gjr",
"modified": "2026-04-18T00:56:28Z",
"published": "2026-03-26T21:34:18Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/openclaw/openclaw/security/advisories/GHSA-xhq5-45pm-2gjr"
},
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-35624"
},
{
"type": "WEB",
"url": "https://github.com/openclaw/openclaw/commit/630f1479c44f78484dfa21bb407cbe6f171dac87"
},
{
"type": "WEB",
"url": "https://github.com/openclaw/openclaw/commit/a47722de7e3c9cbda8d5512747ca7e3bb8f6ee66"
},
{
"type": "PACKAGE",
"url": "https://github.com/openclaw/openclaw"
},
{
"type": "WEB",
"url": "https://www.vulncheck.com/advisories/openclaw-policy-confusion-via-room-name-collision-in-nextcloud-talk"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:U/C:L/I:L/A:N",
"type": "CVSS_V3"
},
{
"score": "CVSS:4.0/AV:N/AC:H/AT:N/PR:L/UI:N/VC:L/VI:L/VA:N/SC:N/SI:N/SA:N",
"type": "CVSS_V4"
}
],
"summary": "OpenClaw: Nextcloud Talk room allowlist matched colliding room names instead of stable room tokens"
}
GHSA-XXMW-M6V2-9H47
Vulnerability from github – Published: 2023-12-19 00:30 – Updated: 2023-12-28 21:30A reliance on untrusted inputs in a security decision could be exploited by a privileged user to configure the Gallagher Command Centre Diagnostics Service to use less secure communication protocols.
This issue affects: Gallagher Diagnostics Service prior to v1.3.0 (distributed in 9.00.1507(MR1)).
{
"affected": [],
"aliases": [
"CVE-2023-46686"
],
"database_specific": {
"cwe_ids": [
"CWE-807"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2023-12-18T22:15:08Z",
"severity": "MODERATE"
},
"details": "\nA reliance on untrusted inputs in a security decision could be exploited by a privileged\u00a0user to configure the Gallagher Command Centre Diagnostics Service to use less secure communication protocols. \n\nThis issue affects: Gallagher Diagnostics Service prior to v1.3.0 (distributed in 9.00.1507(MR1)).\n\n\n\n",
"id": "GHSA-xxmw-m6v2-9h47",
"modified": "2023-12-28T21:30:37Z",
"published": "2023-12-19T00:30:18Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2023-46686"
},
{
"type": "WEB",
"url": "https://security.gallagher.com/Security-Advisories/CVE-2023-46686"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:U/C:L/I:H/A:N",
"type": "CVSS_V3"
}
]
}
Mitigation MIT-14
Strategy: Attack Surface Reduction
- Store state information and sensitive data on the server side only.
- Ensure that the system definitively and unambiguously keeps track of its own state and user state and has rules defined for legitimate state transitions. Do not allow any application user to affect state directly in any way other than through legitimate actions leading to state transitions.
- If information must be stored on the client, do not do so without encryption and integrity checking, or otherwise having a mechanism on the server side to catch tampering. Use a message authentication code (MAC) algorithm, such as Hash Message Authentication Code (HMAC) [REF-529]. Apply this against the state or sensitive data that has to be exposed, which can guarantee the integrity of the data - i.e., that the data has not been modified. Ensure that a strong hash function is used (CWE-328).
Mitigation MIT-4.2
Strategy: Libraries or Frameworks
- Use a vetted library or framework that does not allow this weakness to occur or provides constructs that make this weakness easier to avoid.
- With a stateless protocol such as HTTP, use a framework that maintains the state for you.
- Examples include ASP.NET View State [REF-756] and the OWASP ESAPI Session Management feature [REF-45].
- Be careful of language features that provide state support, since these might be provided as a convenience to the programmer and may not be considering security.
Mitigation MIT-15
For any security checks that are performed on the client side, ensure that these checks are duplicated on the server side, in order to avoid CWE-602. Attackers can bypass the client-side checks by modifying values after the checks have been performed, or by changing the client to remove the client-side checks entirely. Then, these modified values would be submitted to the server.
Mitigation MIT-16
Strategy: Environment Hardening
When using PHP, configure the application so that it does not use register_globals. During implementation, develop the application so that it does not rely on this feature, but be wary of implementing a register_globals emulation that is subject to weaknesses such as CWE-95, CWE-621, and similar issues.
Mitigation MIT-6
Strategy: Attack Surface Reduction
- Understand all the potential areas where untrusted inputs can enter your software: parameters or arguments, cookies, anything read from the network, environment variables, reverse DNS lookups, query results, request headers, URL components, e-mail, files, filenames, databases, and any external systems that provide data to the application. Remember that such inputs may be obtained indirectly through API calls.
- Identify all inputs that are used for security decisions and determine if you can modify the design so that you do not have to rely on submitted inputs at all. For example, you may be able to keep critical information about the user's session on the server side instead of recording it within external data.
No CAPEC attack patterns related to this CWE.