Feb 20, 2026·5 min read·6 visits
Fulcio failed to anchor regular expressions (`^...$`) when validating OIDC issuer URLs containing wildcards. This allowed attackers to craft malicious URLs that merely *contained* a trusted substring, fooling Fulcio into making HTTP requests to attacker-controlled or internal endpoints (SSRF). Fixed in version 1.8.5.
A classic regular expression oversight in Sigstore Fulcio's MetaIssuer validation allowed attackers to bypass domain allowlists. By embedding trusted domain strings into malicious URLs, attackers could trigger Server-Side Request Forgery (SSRF) via the OpenID Connect discovery process, potentially exposing internal cloud metadata.
Sigstore Fulcio is effectively the bouncer of the modern software supply chain. Its job is to issue short-lived code signing certificates based on OpenID Connect (OIDC) identities. If you can prove you own alice@example.com via Google login, Fulcio gives you a cert. To make this work at scale—especially for dynamic cloud environments like AWS EKS or GCP—Fulcio introduced "MetaIssuers."
Instead of hardcoding every single cluster ID, administrators could define patterns with wildcards, like https://oidc.eks.*.amazonaws.com/id/*. It sounds convenient, a classic ease-of-use feature. But as any security researcher knows, whenever a developer tries to convert a wildcard string into a Regular Expression dynamically, a vulnerability is born. The old adage holds true: "Some people, when confronted with a problem, think 'I know, I'll use regular expressions.' Now they have two problems."
In this case, the second problem was CVE-2026-22772. The logic used to validate these issuers had a gaping hole—it forgot to check where the string started and ended. It's the digital equivalent of a bouncer checking a fake ID, seeing "McLovin" written in crayon on the back of a napkin, and saying, "Close enough, come on in."
The vulnerability lies in how Fulcio's pkg/config/config.go handled the MetaRegex generation. When an administrator configured a pattern with a wildcard *, the code helpfully converted that * into a regex character class [-_a-zA-Z0-9]+. So far, so good.
However, in Go's regexp package (and many others), functions like MatchString search for the pattern anywhere inside the target string unless you explicitly tell them not to. If your regex is abc and the input is xyz_abc_123, it returns true. This is a substring match, not an exact match.
Because the generated regex lacked the start-of-line (^) and end-of-line ($) anchors, the validation logic didn't enforce that the entire URL match the trusted pattern. It only checked if the trusted pattern appeared somewhere inside the URL provided by the user. This effectively turned a strict allowlist into a "does it mention the secret password?" check.
Let's look at the diff. It is painfully simple, yet it highlights how subtle regex bugs can be. The vulnerable code took the configuration string, quoted the meta-characters, swapped the wildcards, and compiled it.
Here is the fix from commit eaae2f2be56df9dea5f9b439ec81bedae4c0978d:
// pkg/config/config.go
func MetaRegex(issuer string) (*regexp.Regexp, error) {
// 1. Escape the input string to treat dots/slashes as literals
quoted := regexp.QuoteMeta(issuer)
// 2. Replace the escaped wildcard with a character set
replaced := strings.ReplaceAll(quoted, regexp.QuoteMeta("*"), "[-_a-zA-Z0-9]+")
// THE FIX: Explicitly anchor the regex to start (^) and end ($)
// Vulnerable version was missing this line:
replaced = "^" + replaced + "$"
return regexp.Compile(replaced)
}Without the ^ and $, a pattern intended to match https://trusted.com would also match http://attacker.com/exploit?padding=https://trusted.com.
To exploit this, we need to bypass the validation check and force Fulcio to make an outgoing HTTP request to a destination of our choice. This is a classic Server-Side Request Forgery (SSRF).
The Setup:
Assume Fulcio is configured to trust https://oidc.eks.us-west-2.amazonaws.com/id/*.
The Attack Chain:
http://attacker.com.iss (Issuer) claim that looks like this:
http://attacker.com/foo?bypass=https://oidc.eks.us-west-2.amazonaws.com/id/123iss claim. Because the regex is unanchored, it finds the valid AWS string inside the query parameter. Validation passes./.well-known/openid-configuration to the attacker's URL and performs a GET request.jwks_uri to a sensitive internal location.This is a Blind SSRF. Fulcio generally won't return the body of the jwks_uri response to the user in the certificate itself. However, in cloud environments, SSRF is often the first step in a "Cloud Break."
If Fulcio is running on AWS EC2, and the attacker points the jwks_uri to http://169.254.169.254/latest/meta-data/iam/security-credentials/, Fulcio will fetch those credentials. While the attacker doesn't see them immediately, they might be leaked if:
Even without data exfiltration, an attacker can map the internal network, identifying which ports are open on localhost or adjacent services.
The remediation is straightforward: Update to Fulcio v1.8.5.
If you cannot update immediately, your only mitigation is to disable wildcards in your MetaIssuer configuration. Use exact, full URL matches for your OIDC issuers. If you don't use wildcards, the vulnerable MetaRegex function is likely not invoked in the same hazardous way (or you can rely on static issuer lists).
For developers reading this: this is your reminder that MatchString is not FullMatch. If you are validating security boundaries with Regex, always wrap your pattern in ^ and $.
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:L/I:N/A:N| Product | Affected Versions | Fixed Version |
|---|---|---|
Fulcio Sigstore | < 1.8.5 | 1.8.5 |
| Attribute | Detail |
|---|---|
| Attack Vector | Network (SSRF) |
| CVSS v3.1 | 5.8 (Medium) |
| CWE | CWE-918 (Server-Side Request Forgery) |
| Exploit Status | Proof of Concept |
| EPSS Score | 0.00009 |
| Patch Commit | eaae2f2be56df9dea5f9b439ec81bedae4c0978d |
The software does not properly validate that the input matches the entire regular expression, allowing for substring matches that bypass security checks.