{"answers":{"affected":"3 open source packages ship an affected version, including github.com/0xERR0R/blocky.","exploited":"There is no known exploitation of GHSA-x845-2f78-7v36 in the wild and no public exploit code.","fix":"Upgrade github.com/0xERR0R/blocky to 0.32.0 or later.","what":"GHSA-x845-2f78-7v36 is a vulnerability in github.com/0xERR0R/blocky, published on 19 Jun 2026. An attacker can exploit it over the internet without logging in, with no action from the victim."},"fix_prompt":"Check this codebase for GHSA-x845-2f78-7v36 and fix it if it is affected.\n\nWhat it is: GHSA-x845-2f78-7v36 is a vulnerability in github.com/0xERR0R/blocky, published on 19 Jun 2026. An attacker can exploit it over the internet without logging in, with no action from the victim.\nExploitation: There is no known exploitation of GHSA-x845-2f78-7v36 in the wild and no public exploit code.\n\nAffected packages and fixed versions:\n- github.com/0xERR0R/blocky (Go): affected from 0.28.0; fixed in 0.32.0\n- github.com/0xERR0R/blocky (Go): affected from 0.28.0; fixed in 0.32.0\n- github.com/0xERR0R/blocky (Go): affected from 0.28.0; fixed in 0.32.0\n\nTask:\n1. Search the dependency manifests and lockfiles (for example package.json, package-lock.json, requirements.txt, poetry.lock, uv.lock, pom.xml, build.gradle, go.mod, Cargo.lock, Gemfile.lock) and any Dockerfiles for the affected packages, including transitive dependencies.\n2. If an affected version is in use, upgrade it to the fixed version for its release line with the project's package manager, so the lockfile is regenerated. Prefer the smallest upgrade that fixes it.\n3. If there is no fix, or the upgrade would break the build, do not guess: explain the risk and the safest workaround instead.\n4. Run the tests and summarise what changed and why.\n5. If nothing in the project is affected, say so and change nothing.\n\nReference: https://insights.sbomify.com/GHSA-x845-2f78-7v36/ (Markdown: https://insights.sbomify.com/GHSA-x845-2f78-7v36/index.md)","id":"GHSA-x845-2f78-7v36","markdown":"https://insights.sbomify.com/GHSA-x845-2f78-7v36/index.md","name":"GHSA-x845-2f78-7v36","record":{"aliases":["GO-2026-5745"],"analysis":{"component_type":"server_software","fix_type":"no_fix_stated","impacts":["security_bypass","data_modify"],"network_reachable":"yes","non_default_config":false,"product_category":"DNS proxy server","requires_auth":"none","summary":"Blocky DNS proxy bypasses DNSSEC validation and caches forged answers, allowing attackers to poison DNS responses and redirect traffic.","user_interaction":"not_required","vuln_class":"security_feature_bypass"},"analysis_generated_by":"qwen3.8-flash-next","assigner":null,"cpe":[],"cvss":{"score":null,"severity":null,"source":null,"vector":null,"version":null},"cwes":[],"description":"## 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'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.\n\n## DNSSEC validation Configuration\n\nThe PoCs use Blocky's documented DNSSEC configuration model. This is not a misconfiguration.\n\nBlocky's 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'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.\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.","ecosystems":["Go"],"exploits":{"exploitdb":null,"first_seen":null,"github_poc":null,"max_poc_stars":null,"metasploit":null,"nuclei":null,"refs":[],"tier":null},"has_fix":true,"headline":"Blocky DNSSEC validation bypass and validation-cache scope pollution","id":"GHSA-x845-2f78-7v36","indexable":true,"kev":null,"kind":"advisory","links":{"ecosystem":"Go","product":null,"products":[],"type":"security_feature_bypass","year":"2026"},"n_packages":3,"n_references":null,"packages":[{"ecosystem":"Go","fixed":["0.32.0"],"introduced":["0.28.0"],"last_affected":[],"package":"github.com/0xERR0R/blocky","purl":null,"source":"GHSA-x845-2f78-7v36"},{"ecosystem":"Go","fixed":["0.32.0"],"introduced":["0.28.0"],"last_affected":[],"package":"github.com/0xERR0R/blocky","purl":"pkg:golang/github.com/0xERR0R/blocky","source":"GHSA-x845-2f78-7v36"},{"ecosystem":"Go","fixed":["0.32.0"],"introduced":["0.28.0"],"last_affected":[],"package":"github.com/0xERR0R/blocky","purl":"pkg:golang/github.com/0xERR0R/blocky","source":"GO-2026-5745"}],"products":null,"published":"2026-06-19","related":[],"sources":[{"class":"attribution","licence":"CC BY 4.0","name":"GitHub Advisory Database","prefix":"GHSA"},{"class":"attribution","licence":"CC BY 4.0","name":"Go Vulnerability Database","prefix":"GO"}],"ssvc":{"automatable":null,"exploitation":null,"technical_impact":null},"state":null,"updated":null,"vendors":null},"summary":"Blocky DNS proxy bypasses DNSSEC validation and caches forged answers, allowing attackers to poison DNS responses and redirect traffic.","url":"https://insights.sbomify.com/GHSA-x845-2f78-7v36/"}