Fail-Open URL Inspection in Google Cloud Model Armor Enables a Padding Bypass
Google Cloud Model Armor's malicious URL filter inspects only the first 40 URLs in a prompt or response, and the API gives callers no signal when scanning was partial.
Google Cloud Model Armor's malicious URL filter evaluates only the first 40 URLs in a prompt or response. URLs beyond that limit are not evaluated, and the API response does not indicate that scanning was partial.
This creates an integration risk: downstream systems may treat a successful NO_MATCH_FOUND response as evidence that all URLs were evaluated, when in reality only a prefix of the input was scanned. An attacker who controls URL ordering can exploit this behavior by placing benign URLs first and pushing a malicious URL beyond the inspection boundary.
How We Found It
While testing Model Armor as part of our threat modeling work, we noticed a statement in the documentation that claimed the service inspected up to 40 malicious URLs.
That wording immediately raised a question:
How can a system know a URL is malicious before inspecting it?
To validate the behavior, we built controlled test cases using combinations of benign URLs and Safe Browsing phishing test URLs.
Our testing showed that inspection is positional. Model Armor scans only the first 40 URLs in the input, regardless of whether they are benign or malicious.
Documented Behavior vs Runtime Behavior
| Aspect | Documented Behavior | Runtime Behavior |
|---|---|---|
| Inspection Scope | First 40 malicious URLs | First 40 URLs total |
| URLs Excluded | URLs beyond the malicious URL limit | Any URL beyond position 40 |
| Signal to Caller | Implied inspection according to documented logic | No warning or indication that URLs were skipped |
Reproduction Input
https://example.com/1
https://example.com/2
...
https://example.com/40
# Position 41
https://testsafebrowsing.appspot.com/s/phishing.html
When the Safe Browsing test URL appeared within the first 40 positions, it was detected. When moved beyond position 40, no detection occurred.
Proof of Concept
A reproducible proof-of-concept containing the test code and validation steps used during this research is available here:
The Fail-Open Problem
The issue is not the existence of a processing limit. Many security controls enforce limits. The issue is that Model Armor provides no indication when the limit is reached. In our testing, requests containing malicious URLs beyond the inspection boundary returned:
{
"invocationResult": "SUCCESS",
"filterMatchState": "NO_MATCH_FOUND"
}
The response does not indicate that:
- Scanning stopped after the first 40 URLs
- Additional URLs were skipped
- Inspection was incomplete
This creates a fail-open condition for integrations that treat SUCCESS and NO_MATCH_FOUND as authoritative allow signals. In those designs, uninspected content may continue through the system as though it had been fully evaluated.
Padding Bypass
Because URL inspection is positional, an attacker who controls input ordering can use benign URLs as padding:
- Place 40 benign URLs at the beginning of the prompt or response.
- Place a malicious URL at position 41 or later.
- Rely on the integration to treat
NO_MATCH_FOUNDas a complete allow decision.
The malicious URL falls outside the inspection window and may evade inspection entirely.
URLs 1-40 -> inspected
──────────── inspection boundary ────────────
URL 41+ -> not inspected
URL 41 -> malicious URL
This follows the same pattern as other padding bypasses, where benign content is used to push malicious content beyond a system's inspection boundary.
Responsible Disclosure
We reported the issue to Google Cloud through coordinated disclosure.
Timeline
- March 11, 2026: Issue identified and shared internally
- March 16, 2026: Case opened with Google Cloud
- March 18, 2026: Issue acknowledged
- March 20, 2026: Documentation updated
- May 18, 2026: Feature request submitted for a truncation indicator
Following disclosure, Google updated the documentation to state that only the first 40 URLs are scanned. The original documentation stated that Model Armor inspected up to 40 malicious URLs. That wording implied the service would identify and evaluate malicious URLs regardless of their position in the input. The updated documentation makes a different claim entirely: Model Armor scans only the first 40 URLs encountered and ignores the rest.
However, the runtime behavior remains unchanged. URLs beyond the first 40 positions are not inspected, and the API still does not indicate that scanning was incomplete.
Google confirmed that this behavior is currently expected and recommended that integrations account for the limit themselves.
Mitigations
Google provided several recommendations for deployments that process large numbers of URLs:
- Account for the 40-URL inspection limit when designing downstream trust decisions.
- Count URLs before sending content to Model Armor.
- Split large inputs into multiple requests to ensure all URLs are scanned.
- Use application logging and monitoring to identify inputs that likely exceeded the inspection limit.
We also submitted a feature request asking Google to expose a truncation indicator similar to the findings_truncated field already used by other Model Armor filters.
The control becomes shared between Google and the integrator:
| Risk | Detection signal | Mitigation control | Owner | TrustOnCloud Control ID |
|---|---|---|---|---|
| Prefix-padding bypass | URL count greater than 40 in input | Chunk input into 40-URL or smaller requests | Integration layer | Securitycenter.C84 |
| Partial-scan fail-open | No findings_truncated field in response | Log URL counts; treat over-limit responses as untrusted | Integration layer | Securitycenter.C85 |
| Attacker-controlled input ordering | User-supplied or model-generated URL list | Normalize and reorder before submission; prioritize by source trust | Application layer | Securitycenter.C84 |
| Single-control reliance | Model Armor SUCCESS is treated as authoritative | Layer with independent URL screening; do not rely on Model Armor alone | Architecture | Securitycenter.C84 |
Conclusion
The most significant finding is not that Model Armor scans only 40 URLs. The more important issue is that callers receive no indication when that limit is reached.
As a result, applications may treat partially scanned input as fully evaluated. Until a truncation indicator is available, integrations should assume that large URL sets may have been only partially inspected and design their trust decisions accordingly.
