Metabase is a popular open-source tool for exploring and visualizing data. It’s commonly used to build dashboards and share insights within organizations. One of the powerful features Metabase offers is the ability to embed dashboards in other web applications. To prevent misuse, Metabase includes "locked parameters" — a security measure that pins dashboard filters to certain values when embedded, so viewers can’t see sensitive or irrelevant data.

But in late 2022, a security vulnerability (CVE-2022-39358) was discovered. This allowed attackers to bypass locked parameters and access or manipulate data they weren’t supposed to. If you’re running Metabase and use embedding, this is a vulnerability you should be aware of.

In this post, we’ll break down what CVE-2022-39358 is, how the exploit worked (with code snippets), and where you can find the patch and original disclosures.

What is CVE-2022-39358?

CVE-2022-39358 describes a security flaw in Metabase before certain patched versions. If you built dashboards with "locked parameters" and shared them via embedding links, a crafty attacker could modify network requests in a way that ignored those locks — potentially exposing data you intended to keep hidden.

Understanding Locked Parameters

In an embedded dashboard, you can specify a filter to always use a fixed value. For example, you might show sales only for "USA" by locking the country parameter to USA in the embedding code. The expected behavior is that users can’t change country to, say, China or France by interacting with the dashboard. This is vital for data privacy when embedding dashboards in customer-facing websites.

1. The Attack Surface

When someone views an embedded dashboard, their browser communicates with Metabase’s backend API to fetch data — often by submitting a JSON object specifying filter values.

Normal locked parameter request structure

{
    "parameter_values": {
        "country": "USA"
    }
}

2. Malicious Payload

A determined attacker could go into developer tools in their browser, intercept the network request, and manually change the value, or even add extra parameters to this JSON.

Malicious request spoofed by attacker

{
    "parameter_values": {
        "country": "France"  // Changed from "USA"
    }
}

Metabase should have ignored this and stuck with "USA", but due to the vulnerability, it processed the attacker's input.

3. What the Backend Missed

The root of the problem was that Metabase’s backend trusted the incoming filter values without properly checking if the parameter was marked as "locked" in the dashboard definition. So, by directly hitting the API, the attacker could:

Here’s a pseudo-code outline of the missing validation

# Expected: Only apply parameters not locked
if not parameter_is_locked(param):
    use_parameter_value_from_request()
else:
    use_locked_value()
# Actual: The backend just accepted whatever was in the request
use_parameter_value_from_request()

3. Open Developer Tools: Intercept a network request made to Metabase’s /api/card/:card-id/query or similar endpoint.
4. Modify Request Data: Edit the payload in-flight, replacing locked parameters with attacker-chosen values.
5. Replay/Send Modified Request: Send the edited request, and Metabase returns data for attacker’s custom filters — bypassing the "locked" restriction.

Suppose a company embeds a dashboard like this

<iframe src="https://metabase.yourcompany.com/public/dashboard/abc123?country=USA"></iframe>;

If the attacker intercepts the data query made inside the iframe, they might modify it in a tool like Postman or by hacking their browser’s network inspector:

Original POST request

POST /api/card/42/query
{
    "parameter_values": {
        "country": "USA"
    }
}

Modified POST request

POST /api/card/42/query
{
    "parameter_values": {
        "country": "China"
    }
}

Unexpectedly, Metabase would process the request and return data for "China" — all without authentication or authorization.

.42.6, 1.42.6

What changed?  
After the fix, the backend checks if a parameter is "locked". Even if an attacker tries to override it via the API, the server uses the locked value and ignores the attacker’s input.

if (isLocked(param)) {
    value = lockedValue;
} else {
    value = userProvidedValue;
}

References

- GitHub Advisory - CVE-2022-39358
- NVD CVE Record
- Metabase Release Notes

Final Thoughts

CVE-2022-39358 is a classic example of how client-side controls alone aren’t enough for security — the backend must *always* enforce access restrictions. The fact that it affected all versions before late 2022 makes it an important upgrade for any Metabase deployment.

Recommended Action:

Always test "locked parameters" and similar security features after upgrades or customizations.

For more deep dives like this or to ask questions, leave a comment or check the original advisories linked above. Stay safe, and don’t let your data leak through a dashboard!

Timeline

Published on: 10/26/2022 19:15:00 UTC
Last modified on: 10/28/2022 16:04:00 UTC