CVE-2026-22772: Unanchored Trust in Sigstore Fulcio
Jan 13, 2026·6 min read
Executive Summary (TL;DR)
Fulcio uses regular expressions to validate trusted OIDC providers via 'MetaIssuers'. The generated regexes were missing start and end anchors ('^' and '$'). This allows an attacker to embed a trusted domain string anywhere in a malicious URL (e.g., as a query parameter) to bypass validation and force Fulcio to connect to arbitrary internal or external hosts.
A classic regex implementation failure in Sigstore Fulcio allows attackers to bypass OIDC issuer whitelists, leading to Blind Server-Side Request Forgery (SSRF).
The Hook: Trust Without Anchors
Sigstore Fulcio is the shiny new toy in the software supply chain security world. It acts as a Root CA that issues short-lived code-signing certificates based on OIDC identities. In plain English: you log in with Google, GitHub, or Microsoft, and Fulcio gives you a certificate that says, "Yes, this person signed this code."
To make this work, Fulcio needs to talk to OIDC providers (Issuers) to verify tokens and fetch public keys. Because letting a CA talk to just any server on the internet is a bad idea, Fulcio allows administrators to define a whitelist of trusted issuers using the MetaIssuers configuration. This supports wildcards, so an admin can say "Trust anything looking like https://oidc.eks.*.amazonaws.com".
It sounds secure on paper. But as with most things in security, the devil is in the implementation details—specifically, in how we translate human intent (wildcards) into machine logic (regular expressions). CVE-2026-22772 is the story of what happens when you build a security gate but forget to put a wall around it.
The Flaw: Regex is a Footgun
The vulnerability lies in the metaRegex function within pkg/config/config.go. The goal of this function is simple: take a configuration string like https://issuer.example.com/* and turn it into a Go regular expression that the server can use to validate incoming Issuer URLs.
The logic was straightforward: escape the special characters and replace the wildcard * with a character class [-_a-zA-Z0-9]+. However, the developers missed the most common pitfall in regex generation: anchoring.
In Go (and many other languages), regexp.MatchString checks if the pattern exists anywhere inside the target string. It does not enforce that the pattern matches the entire string unless you explicitly tell it to using ^ (start of string) and $ (end of string). Without these anchors, the validation logic effectively became: "Does this URL contain the trusted domain?" rather than "Is this URL the trusted domain?"
The Code: Autopsy of a Bad Regex
Let's look at the smoking gun. This is the code responsible for generating the validator regex before the patch. It takes the administrator's input and compiles it directly.
// Vulnerable Code in pkg/config/config.go
func metaRegex(issuer string) (*regexp.Regexp, error) {
// 1. Escape the input so dots aren't regex wildcards
quoted := regexp.QuoteMeta(issuer)
// 2. Replace the user's * with a regex character class
replaced := strings.ReplaceAll(quoted, regexp.QuoteMeta("*"), "[-_a-zA-Z0-9]+")
// 3. THE BUG: Compiling without ^ and $
return regexp.Compile(replaced)
}If an admin configured https://trusted.com, the resulting regex was literally https://trusted\.com. If an attacker submits http://evil.com/?ignore=https://trusted.com, the regex engine sees the match in the query parameter and returns true. The validation passes, and Fulcio proceeds to connect to http://evil.com.
The fix was painfully simple. They just had to force the regex to match the full string boundary:
- return regexp.Compile(replaced)
+ replaced = "^" + replaced + "$"
+ return regexp.Compile(replaced)The Exploit: Surfing the Substring
To exploit this, we need to trick Fulcio into making an HTTP request to a server we control (or an internal IP), while convincing the validator that we are a trusted OIDC provider. Let's assume the admin trusts https://oidc.eks.us-east-1.amazonaws.com/id/*.
Step 1: The Setup
We set up a malicious server at attacker.com. We also need to craft a URL that satisfies the unanchored regex. We can simply append the trusted domain as a query parameter or a path fragment that gets ignored by our server.
Step 2: The Trigger
We send a certificate request to Fulcio specifying our Issuer as:
http://attacker.com/foo?bypass=https://oidc.eks.us-east-1.amazonaws.com/id/123
Fulcio's validator scans the string. It finds https://oidc.eks.us-east-1.amazonaws.com/id/123 inside the query parameter. The regex matches. Validation passes.
Step 3: The SSRF
Fulcio now performs OIDC Discovery. It takes the entire URL (scheme and host included) and appends /.well-known/openid-configuration. It sends a GET request to:
http://attacker.com/foo/.well-known/openid-configuration?bypass=...
Step 4: The Pivot
Our malicious server responds with a valid JSON OIDC configuration, but we point the jwks_uri (where keys are stored) to a sensitive internal target.
{
"issuer": "http://attacker.com...",
"jwks_uri": "http://169.254.169.254/latest/meta-data/iam/security-credentials/"
}Fulcio parses this and immediately tries to GET the jwks_uri. It connects to the AWS Metadata service. While Fulcio won't return the AWS keys to us (it expects a JSON Web Key Set, not IAM credentials), we have successfully forced the server to solicit sensitive internal data.
The Impact: Blind but Dangerous
This vulnerability is classified as Blind SSRF. Fulcio expects specific JSON formats (OIDC config and JWKS) in the response. If the internal service returns something else (like raw IAM strings or HTML), Fulcio will likely log an error and fail the certificate issuance. It won't conveniently echo the internal data back to the attacker in the HTTP response.
However, "Blind" does not mean "Harmless".
- Internal Port Scanning: Attackers can probe internal networks by timing how long requests take to fail. A quick RST packet vs. a timeout reveals infrastructure.
- Side Effects: Some internal APIs perform actions on GET requests (which is bad design, but common). An attacker could trigger these.
- WAF/Filter Bypass: Since the request originates from the trusted Fulcio server inside the network, it bypasses perimeter firewalls.
This is like a burglar who can't steal your TV, but can ring every doorbell in your house to see who's home.
The Fix: Dropping the Anchor
The remediation is straightforward: Update to Fulcio v1.8.5.
The patch explicitly anchors the regex, ensuring that the MetaIssuers pattern must match the entire provided URL, not just a part of it. If you cannot patch immediately, you are in a tough spot, as this is a logic flaw in the configuration parsing itself—there is no configuration workaround other than disabling MetaIssuers or being extremely restrictive with your network egress policies.
For developers reading this: this is your daily reminder that Matches usually means Contains. If you mean Equals, use ^...$. Always anchor your regexes unless you have a very specific reason not to.
Official Patches
Fix Analysis (1)
Technical Appendix
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:L/I:N/A:NAffected Systems
Affected Versions Detail
| Product | Affected Versions | Fixed Version |
|---|---|---|
Sigstore Fulcio Sigstore | < 1.8.5 | 1.8.5 |
| Attribute | Detail |
|---|---|
| CVE ID | CVE-2026-22772 |
| CWE ID | CWE-918 |
| CVSS Score | 5.8 (Medium) |
| Attack Vector | Network |
| Impact | Blind SSRF / Information Disclosure |
| Exploit Status | PoC Available (Theoretical) |
MITRE ATT&CK Mapping
The application sends a request to a server that matches a regular expression, but the regular expression is not anchored, allowing the request to be sent to an arbitrary server if the trusted pattern appears anywhere in the URL.
Known Exploits & Detection
Vulnerability Timeline
Subscribe to updates
Get the latest CVE analysis reports delivered to your inbox.