fix(security): stop curl_command from carrying the bearer token across a redirect - #525
Merged
Merged
Conversation
…s a redirect curl_command() passed -L, so a redirect was followed with the OAuth bearer token still on curl's configuration input. curl fixed the cross-host case in 7.58.0 as CVE-2018-1000007, which leaves roughly 7.30 through 7.57 exposed. Measured against the live API: every endpoint curl_command touches answers in a single hop on the correct region, including download-installer/v3 and the registry tags list. So -L never fired on a correct-region run. -L only did work when FALCON_CLOUD named the wrong region, because the API answers a wrong region with a 308 to the right one. That never worked on a curl that strips the header, which is every supported version: on curl 7.29.0 and 8.5.0 the redirect was followed, the header was dropped, the call came back 401 and the run died with a misleading "No sensor found for OS" error. The only versions where -L produced a working request are the same versions that leak the token. Dropped -L, and with it --proto-redir, keeping the convention from #521 that --proto-redir appears only next to -L. The wrong-region case is now handled the way the OAuth token request already handles it: the x-cs-region hint is adopted instead of the redirect being followed, so it works on every curl version rather than only the leaky band. The warning naming the real region still prints. falcon-container-sensor-pull.sh already adopted the hint; install, uninstall and migrate only warned and kept the wrong region. Fixes #523
…following it Dropping -L closed the leak but left the wrong-region case relying on get_oauth_token having corrected cs_falcon_cloud first. That only covers the client id and secret path: with FALCON_ACCESS_TOKEN there is no token POST, so there is no x-cs-region to read, and every API call went to the wrong region. curl_command now reads x-cs-region off the un-followed redirect and re-issues against that region, resolved through cs_cloud(), so the retry host always comes from a closed allowlist and never from Location. Region correction now covers every request that carries the token, whichever way the token was obtained. There is no scope-free way to discover this up front: the 308 only comes back on a real routable path. An unknown path answers 404 with no x-cs-region, and the redirect is emitted after authentication, so an unauthenticated probe gets 401. The retry therefore rides on the caller's own request rather than a probe. The body is buffered because the redirect body is 107 bytes, not empty, so emitting it would corrupt the value the caller captures. Buffering is safe for the -o callers too: curl writes their file itself and stdout stays empty. The status is read from the last HTTP status line, because a proxy CONNECT dumps one of its own first. The exit code is captured and returned so behaviour under set -e is unchanged and #526's call-site guards still receive the real code - measured: rc=5 for an unresolvable proxy, both under set +e and through a command substitution. Verified against the live API on curl 7.29.0 and 8.5.0, with client credentials and with FALCON_ACCESS_TOKEN, for us-1, us-2 and eu-1: GET, GET with -o, PATCH with a JSON body, and the query holding a literal pipe all reach the correct region. The arg rewrite was checked separately under dash, bash and macOS sh.
redhatrises
approved these changes
Sep 9, 2026
This was referenced Sep 9, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #523.
curl_command()in the four bash scripts passed-L, so a redirect was followed with the OAuth bearer token still sitting on curl's configuration input. curl fixed the cross-host case in 7.58.0 as CVE-2018-1000007, which leaves roughly 7.30 through 7.57 exposed.I measured every endpoint
curl_commandtouches against the live API. All of them answer in a single hop on the correct region — includingsensors/entities/download-installer/v3, which I had assumed redirected to a CDN, and the registry tags list onregistry.crowdstrike.com. So on a correct-region run-Lnever fired at all.The one case where it did something was a wrong region, because the API answers a wrong region with a 308 to the right one. That path never actually worked on a curl that strips the header, which is every version anyone still runs: on both curl 7.29.0 and 8.5.0 the redirect was followed, the header was dropped, the call came back 401, and the run died with a misleading
No sensor found for OS: Ubuntu, Version: 24. The only curl versions where-Lproduced a working request are the same ones that leak the token.So
-Lis gone, and--proto-redirwith it, keeping the convention from #520/#521 that--proto-redironly appears next to-L. In its placecurl_commandreadsx-cs-regionoff the un-followed redirect and re-issues against that region, resolved throughcs_cloud(). The retry host therefore always comes from a closed allowlist and never fromLocation, which is the part an attacker would control. This is the same shape as the OAuth token retry in #521, and it means region correction now covers every request carrying the token rather than only the ones made afterget_oauth_tokenhad corrected the cloud. That matters forFALCON_ACCESS_TOKEN: there is no token POST on that path, so there is nox-cs-regionto read up front, and onmainevery API call went to the wrong region and failed.There is no way to discover the region up front without picking a scope. The 308 only comes back on a real routable path — an unknown path answers 404 with no
x-cs-region— and it is emitted after authentication, so an unauthenticated probe just gets 401. Riding on the caller's own request avoids assuming any particular scope, and costs nothing when the region is already right.Two details worth flagging in review. The body is buffered to a temp file because the redirect body is 107 bytes rather than empty, so letting it through would corrupt the value the caller captures; that is safe for the
-ocallers because curl writes their file itself and stdout stays empty. And the status is taken from the lastHTTP/line in the dump, because a proxyCONNECTwrites one of its own first.get_oauth_tokenalso now adopts the hint whenFALCON_CLOUDdisagrees with it, instead of warning and then continuing to the wrong region. That is not needed for correctness any more, but it saves a redirect round trip on every subsequent call and it makes the existing warning mean something.falcon-container-sensor-pull.shalready did this; install, uninstall and migrate only warned.Verified against the live tenant on curl 7.29.0 and 8.5.0, with client credentials and with
FALCON_ACCESS_TOKEN, for us-1, us-2 and eu-1: GET, GET with-o, PATCH with a JSON body, and the query holding a literal|all reach the correct region, and the same wrong-region runs fail onmain. The argument rewrite was checked separately under dash, bash and macOS sh. Exit codes are unchanged: an unresolvable proxy still yields 5 through the function, both underset +eand through a command substitution, so #526's call-site guards receive the real code. shfmt (-i 4 -ci, bash and posix) and shellcheck (bash and dash) are clean on all four files.#522 also edits
curl_commandand needs rebasing against main before it goes in.