Exploring CORS Vulnerabilities in Rust: Patterns and Bypasses

Published: 05 Dec 2024

After my recent article on CORS Vulnerabilities in Go: Vulnerable Patterns and Lessons, I started exploring similar issues in Rust. Interestingly, the vulnerabilities are quite similar and easy to spot. Essentially, you only need to look for Rust equivalents of Go's strings.Contains(), strings.HasSuffix(), and strings.HasPrefix(). While I didn’t plan to dive into those common patterns here, I came across a unique strategy worth discussing.

Starts with...

Just like in Go, we can find examples of vulnerable Rust code on GitHub with a few simple searches:

fn set_default_cors(origin: &str, req: &mut Response) {
    if origin.starts_with("https://www.youtube.com")
        || origin.starts_with("https://youtube.com")
        || origin.starts_with("chrome-extension") {
     // ...
    }
}

This snippet checks if the origin starts with https://youtube.com or https://www.youtube.com. Unfortunately, this logic can be bypassed with URLs like http://youtube.com.pentesterlab.com, for example. I quickly reported it and it was quickly fixed.

Contains...

Another example of a vulnerable check can be found in this snippet:

if origin.contains("example.com") || origin.contains("localhost") {

This only checks that the origin contains example.com or localhost. We can bypass this check using example.com.pentesterlab.com, for example.

It's pretty easy to find other examples like:

origin.contains("127.0.0.1") || origin.contains("localhost")
The Strategy That Caught My Interest

This is the code that got me to write this blog post:

pub fn self_pre_link(ctx: &Context) -> String {
    let host = ctx.header("Host");
    let origin = ctx.header("Origin");
    if origin.ends_with(&host) {
        return origin;
    }
}

We can see that the code retrieves the Host and Origin headers and checks if the Origin header ends with the Host header. This is an interesting strategy. Unfortunately, it can be easily bypassed. For example, if the website is hosted under example.com, an attacker can leverage the domain hackingexample.com to bypass the restriction.

Final Thoughts

These are another set of low-hanging fruits that you can easily discover in codebases on GitHub. Even Rust isn’t immune to these kinds of vulnerabilities.

Photo of Louis Nyffenegger
Written by Louis Nyffenegger
Founder and CEO @PentesterLab