A database connection string in your frontend is a direct line to your data
Most leaked secrets give an attacker access to an API - annoying, scoped, revocable. A database connection string is different in kind: it's the database. Host, port, username, and password, all in one string, pointing straight at where your data actually lives. If one ends up in code you serve to the browser, you haven't leaked a key - you've published the address and the password of the vault.
These strings have a shape that's hard to mistake for anything else. A SQL Server or .NET connection string reads Server=...;Database=...;User Id=...;Password=.... An ADO-style one uses Data Source=...;Initial Catalog=.... That distinctive structure - a data-source token and an inline password in the same string - is what makes it both unmistakable and catastrophic.
How it gets to the browser, and what a stranger does with it
It rarely happens on purpose. A connection string lives in a server config, someone wires up a "shared config" object that gets bundled for both server and client, and the bundler happily ships the whole thing to the browser. Or it's hardcoded in a script during a quick test and never removed. Modern database providers have the same trap with their own token formats - a PlanetScale pscale_pw_ or pscale_tkn_, an Azure Storage AccountKey=... connection string - all of which grant data access and all of which can ride a bundle to the client.
What a stranger does with it depends only on whether your database is reachable. If the host is internet-facing - and managed databases very often are - they connect directly with the credentials you handed them: read every row, dump the lot, modify or delete at will. No exploit, no privilege escalation. You gave them the login.
Get it server-side, then rotate
The fix is the same rule that governs every server secret: the credentials that reach a database must never reach a browser.
// shared config bundled to the client
export const db = {
connectionString: "Server=db.internal;User Id=sa;Password=Pr0d_S3cret!"
};
// ^ ships in app.bundle.jsMove the connection string to a server-side environment variable that your bundler never includes in client code, and have the browser talk to your own API endpoints instead of the database directly. Then rotate the credentials - once a password has been served in a public bundle, treat it as compromised, because you have no way to know who already grabbed it. The same goes for a leaked PlanetScale or Azure Storage token: revoke and reissue.
Whether a connection string is sitting in your served JavaScript is something a stranger finds by fetching your bundle and running a regex, which means we check it the same way. SurfaceCheckr scans your served HTML and scripts for the connection-string shape - flagging only when both a data-source token and an inline password are present, so a harmless host-only string doesn't trip it - alongside provider tokens like PlanetScale and the Azure AccountKey= connection string. It reads what's in the bundle and stops there; it never connects to anything. That's the two-minute check that the address and password of your database aren't being handed to every visitor.
Find it before someone else does.
Paste your domain. The grade and issue count are free, and you'll see in a couple of minutes exactly what's reachable from outside.