File size: 39,646 Bytes
8035bff
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
d4f7881
 
8035bff
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
d4f7881
8035bff
5e057ff
8035bff
 
 
 
d4f7881
 
 
 
 
8035bff
 
 
 
 
d4f7881
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
<!doctype html><html lang="en"><meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>Hardcoded Connection String Audit for Azure IoT Hub (azure-iot-toolkit) + 7 More VS Code Stacks — 26 rules, 32 snippets</title>
<meta name="description" content="26 rules and 32 safe-replacement snippets across 8 VS Code stacks. Hosted secret scanning is published at $19 per active committer per month (GitHub Secret Protection pricing page); this is a one-time $29, runs on your machine, and sends nothing anywhere.">
<style>
:root{color-scheme:light dark}
body{margin:0;font:16px/1.6 system-ui,-apple-system,"Segoe UI",sans-serif;
 background:#fbfbfa;color:#16161d}
@media(prefers-color-scheme:dark){body{background:#14141a;color:#e8e8ea}}
.wrap{max-width:880px;margin:0 auto;padding:28px 20px 64px}
h1{font-size:1.7rem;line-height:1.25;margin:.2em 0 .3em}
p.sub{margin:0 0 1.4em;opacity:.8}
textarea{width:100%;min-height:230px;font:13px/1.5 ui-monospace,Menlo,Consolas,monospace;
 padding:12px;border:1px solid #c9c9d1;border-radius:10px;background:transparent;color:inherit;
 box-sizing:border-box}
button{font:600 15px/1 inherit;padding:12px 22px;border:0;border-radius:10px;
 background:#1d4ed8;color:#fff;cursor:pointer;margin:12px 0}
button:hover{background:#1a43bd}
table{border-collapse:collapse;width:100%;margin-top:14px;font-size:14px}
th,td{border-bottom:1px solid #d8d8e0;padding:8px 6px;text-align:left;vertical-align:top}
th{font-weight:600;opacity:.75}
td.n{width:64px;font:13px ui-monospace,monospace;opacity:.7}
.ok{padding:14px;border-radius:10px;background:#e8f5ec;color:#14532d;margin-top:14px}
@media(prefers-color-scheme:dark){.ok{background:#15321f;color:#bbf7d0}}
.next{margin-top:30px;padding:18px;border:1px solid #d8d8e0;border-radius:12px}
.next h2{font-size:1.05rem;margin:0 0 .5em}
.next ul{margin:.3em 0 1em 1.1em;padding:0}
a.buy{display:inline-block;font:600 15px/1 inherit;padding:13px 22px;border-radius:10px;
 background:#1d4ed8;color:#fff;text-decoration:none}
a.buy:hover{background:#1a43bd}
.anchor{font-size:14px;opacity:.85;margin:.2em 0 1em}
.afterhit{margin-top:16px;padding:14px;border:1px solid #d8d8e0;border-radius:10px;font-size:14px}
.afterhit p{margin:0 0 10px}
</style>
<div class="wrap">
<h1>Hardcoded Connection String Audit for Azure IoT Hub (azure-iot-toolkit) + 7 More VS Code Stacks — 26 rules, 32 snippets</h1>
<p class="sub">26 rules and 32 safe-replacement snippets across 8 VS Code stacks. Hosted secret scanning is published at $19 per active committer per month (GitHub Secret Protection pricing page); this is a one-time $29, runs on your machine, and sends nothing anywhere.</p>
<textarea id="src" placeholder="Paste the file here"></textarea>
<button id="go">Check</button>
<div id="out"></div>
<div class="next">
<h2>What a licence adds</h2>
<ul>
<li><b>Scale</b> — the same 26 rules across every file in the workspace, not the one file you have open.</li>
<li><b>Handover</b> — the findings written out as a CSV, JSON or HTML file you keep in the repo and hand to a reviewer.</li>
</ul>
<p class="anchor">GitHub Secret Protection is published at <b>$19 per active committer per month</b>, billed for as long as the team keeps committing. This is <b>$29 once</b>, runs on your machine, and sends nothing anywhere.</p>
<a class="buy" href="https://getreadystack.com/api/buy/cl/polar_cl_1tgGYRxH9pxpXj2qrSYA5SmeCbtVqYcXEKLoD4CR3y7">Get the full version — $29 once</a>
</div>
</div>
<script>
var RULES=[{"pattern": "HostName=[^;\\s\"']+\\.azure-devices\\.net;[^\\n]*SharedAccessKey=[A-Za-z0-9+/=]{16,}", "flags": "i", "message": "An IoT Hub connection string with a live SharedAccessKey is written into this file. Anyone who clones the repository can send and receive on that device identity.", "fix": "HostName=${IOTHUB_HOSTNAME};DeviceId=${IOTHUB_DEVICE_ID};SharedAccessKey=${IOTHUB_DEVICE_KEY}"}, {"pattern": "SharedAccessSignature\\s+sr=[^&\\s]+&sig=[A-Za-z0-9%+/=]{16,}", "flags": "i", "message": "A SAS token is pasted here. It works until it expires and it cannot be revoked on its own without regenerating the policy key.", "fix": "SharedAccessSignature=${IOTHUB_SAS_TOKEN}"}, {"pattern": "symmetricKey\\s*[:=]\\s*[\"'][A-Za-z0-9+/=]{20,}[\"']", "flags": "i", "message": "A Device Provisioning Service symmetric key is hardcoded. Read it from the environment, or provision with an X.509 certificate instead."}, {"pattern": "DefaultEndpointsProtocol=https?;AccountName=[^;]+;AccountKey=[A-Za-z0-9+/=]{40,}", "flags": "i", "message": "A storage account key is in this file. That key grants full read and write on every container in the account, including IoT file uploads.", "fix": "DefaultEndpointsProtocol=https;AccountName=${AZURE_STORAGE_ACCOUNT};AccountKey=${AZURE_STORAGE_KEY}"}, {"pattern": "Endpoint=sb://[^;]+;SharedAccessKeyName=[^;]+;SharedAccessKey=[A-Za-z0-9+/=]{16,}", "flags": "i", "message": "An Event Hubs or Service Bus connection string with its key is hardcoded. This is usually the telemetry endpoint the whole device fleet writes to.", "fix": "Endpoint=${EVENTHUB_ENDPOINT};SharedAccessKeyName=${EVENTHUB_KEY_NAME};SharedAccessKey=${EVENTHUB_KEY}"}, {"pattern": "(?:Server|Data Source)=[^;\\n]+;[^\\n]*(?:Password|Pwd)=[^;\"'\\s]{4,}", "flags": "i", "message": "A SQL Server connection string carries the password inline. Use Microsoft Entra authentication, or read the whole string from the environment.", "fix": "Server=${SQL_SERVER};Database=${SQL_DATABASE};Authentication=Active Directory Default;Encrypt=true"}, {"pattern": "TrustServerCertificate\\s*=\\s*(?:true|yes)", "flags": "i", "message": "TrustServerCertificate is on, so the driver accepts any certificate and the encrypted connection can be intercepted.", "fix": "TrustServerCertificate=false"}, {"pattern": "jdbc:sqlserver://[^\\s\"']*(?:password|Password)=[^;\\s\"']{4,}", "flags": "", "message": "A JDBC URL for SQL Server contains the password. JDBC URLs end up in logs and stack traces.", "fix": "jdbc:sqlserver://${SQL_SERVER};database=${SQL_DATABASE};authentication=ActiveDirectoryDefault;encrypt=true"}, {"pattern": "\"password\"\\s*:\\s*\"[^\"]{4,}\"", "flags": "", "message": "A saved connection stores the password in plain JSON. Let the client ask for it at connect time instead.", "fix": "\"askForPassword\": true"}, {"pattern": "(?:client-key-data|client-certificate-data|token):\\s*[A-Za-z0-9+/=._-]{40,}", "flags": "", "message": "A kubeconfig credential is committed here. It authenticates to the cluster from any machine that has this file."}, {"pattern": "az\\s+aks\\s+get-credentials[^\\n]*--admin", "flags": "i", "message": "This fetches the cluster-admin certificate, which is not tied to a user and cannot be revoked for one person. Fetch user credentials instead.", "fix": "az aks get-credentials --resource-group ${AKS_RESOURCE_GROUP} --name ${AKS_CLUSTER_NAME}"}, {"pattern": "--docker-password[=\\s]+[^\\s\"']{4,}", "flags": "", "message": "A registry password is passed on the command line. It lands in shell history and in CI logs.", "fix": "--docker-password=${REGISTRY_PASSWORD}"}, {"pattern": "Preferences(?:\\.Default)?\\.Set\\s*\\(\\s*\"[^\"]*(?:token|password|secret|key)[^\"]*\"", "flags": "i", "message": "A secret is being written to Preferences, which is unencrypted on the device. Use SecureStorage, which uses the platform keystore."}, {"pattern": "\"(?:ApiKey|ClientSecret|ConnectionString|AccountKey)\"\\s*:\\s*\"[^\"]{8,}\"", "flags": "", "message": "A secret sits in an appsettings file that ships inside the app package. Anyone can unzip the package and read it."}, {"pattern": "const\\s+string\\s+\\w*(?:ApiKey|Secret|Token|Password)\\w*\\s*=\\s*\"[^\"]{8,}\"", "flags": "i", "message": "A credential is compiled in as a constant. It stays readable in the assembly with any decompiler."}, {"pattern": "^[\\t ]*[\\w.-]*(?:password|secret|api[-_.]?key|token)[\\w.-]*\\s*=\\s*\\S{4,}$", "flags": "im", "message": "A configuration property holds a real value. MicroProfile Config reads environment variables first, so leave the value out of the file."}, {"pattern": "@ConfigProperty\\s*\\([^)]*defaultValue\\s*=\\s*\"[^\"]{12,}\"", "flags": "", "message": "A long defaultValue on @ConfigProperty is a secret baked into the class file. Drop the default and let startup fail loudly when it is missing."}, {"pattern": "add\\(\\s*\"Authorization\"\\s*,\\s*\"(?:Bearer|Basic)\\s+[^\"]{16,}\"", "flags": "", "message": "An Authorization header is hardcoded in the Rest Client. Inject it through config so it can be rotated without a rebuild."}, {"pattern": "Sys\\.setenv\\s*\\(\\s*[\\w.]*(?:KEY|TOKEN|SECRET|PASSWORD|PAT)[\\w.]*\\s*=\\s*[\"'][^\"']{8,}", "flags": "", "message": "Sys.setenv is being called with a literal secret. Put the value in .Renviron, which stays out of git, and read it with Sys.getenv."}, {"pattern": "dbConnect\\s*\\([^)]*password\\s*=\\s*[\"'][^\"']{3,}[\"']", "flags": "i", "message": "A database password is written into the dbConnect call. It will also sit in .Rhistory and in the rendered notebook."}, {"pattern": "options\\s*\\(\\s*[\\w.]*(?:key|token|secret)[\\w.]*\\s*=\\s*[\"'][^\"']{8,}[\"']", "flags": "i", "message": "A key is set through options(), so it is saved with the workspace image and printed by any call that dumps options."}, {"pattern": "add_headers\\s*\\(\\s*Authorization\\s*=\\s*[\"'](?:Bearer|Basic)\\s+[^\"']{16,}", "flags": "", "message": "A bearer token is written into a request chunk. Rendering this document with echo on prints the token into the output file."}, {"pattern": "-----BEGIN (?:RSA |EC |DSA |OPENSSH |PGP )?PRIVATE KEY-----", "flags": "", "message": "A private key block is inside this file. Keep the key on disk outside the repository and pass its path in an environment variable.", "fix": "# private key removed - load it from the path in ${PRIVATE_KEY_PATH}"}, {"pattern": "\\b(?:https?|mongodb|postgres(?:ql)?|amqps?|mqtts?)://[^\\s/:@\"']+:[^\\s/:@\"']+@", "flags": "i", "message": "A user name and password are embedded in a URL. Proxies and error pages copy whole URLs, so this credential travels further than the file."}, {"pattern": "\\bey[A-Za-z0-9_-]{10,}\\.[A-Za-z0-9_-]{10,}\\.[A-Za-z0-9_-]{10,}", "flags": "", "message": "A JSON Web Token is pasted here. It is valid until it expires, and its payload is readable by anyone."}, {"pattern": "^[\\t ]*(?:AWS_SECRET_ACCESS_KEY|AZURE_CLIENT_SECRET|IOTHUB_CONNECTION_STRING|DATABASE_PASSWORD)\\s*=\\s*\\S{6,}$", "flags": "im", "message": "A filled-in secret variable is in a tracked file. Keep values in .env, git-ignore it, and commit .env.example with the names only."}];
function scan(t){var L=String(t).split(/\r?\n/),h=[],i,r,re;
 for(i=0;i<L.length;i++){for(var k=0;k<RULES.length;k++){r=RULES[k];
  try{re=new RegExp(r.pattern,r.flags||'')}catch(e){continue}
  if(re.test(L[i]))h.push({line:i+1,msg:r.message})}}
 return h}
document.getElementById('go').onclick=function(){
 var t=document.getElementById('src').value,o=document.getElementById('out');
 if(!t.trim()){o.innerHTML='';return}
 var h=scan(t);
 if(!h.length){o.innerHTML='<div class="ok">No hardcoded credential matched any of the 26 rules here.</div>';return}
 var s='<table><tr><th>Line</th><th>Finding</th></tr>';
 for(var i=0;i<h.length;i++){s+='<tr><td class="n">'+h[i].line+'</td><td>'+
   String(h[i].msg).replace(/&/g,'&amp;').replace(/</g,'&lt;')+'</td></tr>'}
 o.innerHTML=s+'</table>'+'<div class="afterhit"><p><b>'+h.length+'</b> in this one file. A repository is not one file.</p>'+'<a class="buy" href="https://getreadystack.com/api/buy/cl/polar_cl_1tgGYRxH9pxpXj2qrSYA5SmeCbtVqYcXEKLoD4CR3y7">Audit every file and export the findings \u2014 $29 once</a></div>'};
</script>
</html>


<section data-yj-install="free" style="margin:2rem auto 1rem;max-width:46rem;padding:1.25rem 1.25rem;border:1px solid #cfe3d6;border-radius:12px;background:#f6fbf8;font:16px/1.6 system-ui,-apple-system,Segoe UI,sans-serif"><h2 style="margin:0 0 .4rem;font-size:1.2rem">Install free</h2><p style="margin:0 0 .8rem;color:#41505f">Free for the file open in your editor - no key, no limit. The workspace sweep and the report ask for a key.</p><a href="https://www.npmjs.com/package/@readystack/connection-string-secret-audit" rel="noopener" data-yj-install-door="npm" onclick="try{navigator.sendBeacon('/api/ev',new Blob([JSON.stringify({t:'install',slug:'connection-string-secret-audit',src:'npm',path:location.pathname})],{type:'application/json'}))}catch(e){}" style="display:inline-block;margin:0 .5rem .5rem 0;padding:.6rem 1rem;border-radius:8px;background:#0f7b3f;color:#fff;text-decoration:none;font-weight:600">npm</a><a href="https://www.npmjs.com/package/@readystack/connection-string-secret-audit" rel="noopener" data-yj-install-door="mcp" onclick="try{navigator.sendBeacon('/api/ev',new Blob([JSON.stringify({t:'install',slug:'connection-string-secret-audit',src:'mcp',path:location.pathname})],{type:'application/json'}))}catch(e){}" style="display:inline-block;margin:0 .5rem .5rem 0;padding:.6rem 1rem;border-radius:8px;background:#0f7b3f;color:#fff;text-decoration:none;font-weight:600">MCP server (npx)</a><a href="https://hub.docker.com/r/getreadystack/connection-string-secret-audit" rel="noopener" data-yj-install-door="docker" onclick="try{navigator.sendBeacon('/api/ev',new Blob([JSON.stringify({t:'install',slug:'connection-string-secret-audit',src:'docker',path:location.pathname})],{type:'application/json'}))}catch(e){}" style="display:inline-block;margin:0 .5rem .5rem 0;padding:.6rem 1rem;border-radius:8px;background:#0f7b3f;color:#fff;text-decoration:none;font-weight:600">Docker Hub</a><pre style="margin:.5rem 0 0;padding:.6rem .8rem;background:#f3f5f8;border-radius:8px;font-size:.9rem;overflow:auto">npx @readystack/connection-string-secret-audit &lt;file&gt;
npx @readystack/connection-string-secret-audit --mcp
docker run --rm -v &quot;$PWD:/w&quot; getreadystack/connection-string-secret-audit /w</pre><p style="margin:.6rem 0 0;font-size:.92rem;color:#41505f"><a href="https://getreadystack.com/api/buy/cl/polar_cl_l6iN1uWt0FwWu7tBsczD0jWpP2vxFM54Wdwqb3KPi1G" rel="nofollow" style="color:#0f7b3f;text-decoration:underline">Team? One key for every ReadyStack linter, 5 seats, $149 once</a></p></section>
<section data-yj-alert="rule" style="margin:1rem auto 1.5rem;max-width:46rem;padding:1.1rem 1.25rem;border:1px solid #d9dee6;border-radius:12px;background:#fbfcfd;font:15px/1.55 system-ui,-apple-system,Segoe UI,sans-serif"><b style="font-size:1.05rem">Get the full rule table as a PDF</b><div style="opacity:.78;margin:.35rem 0 .8rem">All 26 rules Connection String &amp; Secret Audit — 8 Stacks checks, each with its source and date, on printable pages you can hand to your team or auditor. We email it now, and once more only if a rule changes. No newsletter.</div><div style="display:flex;gap:8px;flex-wrap:wrap"><input id="yjae" type="email" placeholder="you@example.com" style="flex:1;min-width:210px;padding:11px 13px;border:1px solid rgba(140,150,165,.34);border-radius:8px;background:#fff;color:inherit"><button id="yjab" style="padding:11px 18px;border-radius:8px;border:0;cursor:pointer;background:#0f7b3f;color:#fff;font:600 15px system-ui,sans-serif">Email me the PDF</button></div><div id="yjao" hidden style="margin-top:.6rem;color:#0f7b3f">Sent. It arrives within the hour - check spam too.</div><script>(function(){var b=document.getElementById("yjab"),e=document.getElementById("yjae");if(!b||!e)return;b.addEventListener("click",function(){var v=e.value.trim();if(!/.+@.+\..+/.test(v))return;try{localStorage.setItem("yj_em","1");}catch(_){}fetch(location.origin+"/api/subscribe",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({email:v,slug:"connection-string-secret-audit",lang:"en",source:"rule_table"+((b.closest&&b.closest("section")&&b.closest("section").getAttribute("data-yj-moved"))?"_at_result":"")})}).then(function(r){var o=document.getElementById("yjao");o.hidden=false;if(!r.ok){o.textContent="Could not save - please try again.";}}).catch(function(){var o=document.getElementById("yjao");o.hidden=false;o.textContent="Could not save - please try again.";});});})();</script><script>(function(){var e=document.getElementById("yjae"),s=e&&e.closest?e.closest("section"):null,o=document.getElementById("out");if(!s||!o)return;var d=false;function mv(ev){if(d)return;if(ev&&ev.target&&s.contains(ev.target))return;d=true;var b=o;while(b.parentNode&&b.parentNode!==document.body&&b.parentNode.tagName!=="MAIN"&&b.parentNode.tagName!=="ARTICLE")b=b.parentNode;if(!b.parentNode||b===s||b.contains(s))return;try{b.parentNode.insertBefore(s,b.nextSibling);s.setAttribute("data-yj-moved","1");}catch(_){}}document.addEventListener("input",mv,true);document.addEventListener("change",mv,true);})();</script></section>

<section data-yj-cta="paid" style="margin:3rem auto;max-width:46rem;padding:1.5rem 1.25rem;border:1px solid #d8dee9;border-radius:12px;background:#fbfcfe;font:16px/1.6 system-ui,-apple-system,Segoe UI,sans-serif"><h2 style="margin:0 0 .5rem;font-size:1.25rem">Get the complete version <span class="yj-price">$29</span></h2><p style="margin:.25rem 0 1rem;color:#41505f">This page is the working piece. The full pack has everything below.</p><p style="margin:0 0 1rem;color:#41505f">26 rules and 32 safe-replacement snippets for hardcoded connection strings, keys and kubeconfigs across 8 VS Code stacks. Runs on your machine and sends nothing anywhere.</p><p style="margin:0 0 1rem;color:#5b6b7c;font-size:.94rem">GitHub Secret Protection is published at $19 per active committer per month, billed every month and re-counted as committers come and go (GitHub Docs, checked 2026-09-08)</p><a href="https://getreadystack.com/api/buy/cl/polar_cl_1tgGYRxH9pxpXj2qrSYA5SmeCbtVqYcXEKLoD4CR3y7" rel="nofollow" style="display:inline-block;padding:.7rem 1.3rem;border-radius:8px;background:#1b64f2;color:#fff;text-decoration:none;font-weight:600">Buy the full version — $29</a></section>
<!--yj-share-s101--><div style="margin:28px 0 8px;text-align:center"><button id="yjcp" type="button" style="font:inherit;padding:10px 18px;border:1px solid #8884;border-radius:10px;background:transparent;cursor:pointer">Copy link</button><button id="yjimg" type="button" style="font:inherit;padding:10px 18px;margin-left:8px;border:1px solid #8884;border-radius:10px;background:transparent;cursor:pointer">Save result as image</button></div><script>(function(){var b=document.getElementById("yjimg");if(!b)return;b.addEventListener("click",function(){var o=document.getElementById("out");var txt=(o&&(o.innerText||o.textContent)||"").trim();if(!txt){b.textContent="(no result yet)";setTimeout(function(){b.textContent="Save result as image";},1500);return;}var lines=txt.split(String.fromCharCode(10)).filter(function(x){return x.trim();}).slice(0,10);var W=1200,P=56,c=document.createElement("canvas");c.width=W;var lh=38,H=P*2+70+lines.length*lh+60;c.height=H;var x=c.getContext("2d");x.fillStyle="#1a1512";x.fillRect(0,0,W,H);x.fillStyle="#f3e9d2";x.font="600 34px system-ui,Segoe UI,Arial";var t=(document.title||"").split("|")[0].trim();x.fillText(t.slice(0,54),P,P+34);x.font="22px ui-monospace,Menlo,Consolas,monospace";x.fillStyle="#e8dcc4";for(var i=0;i<lines.length;i++){x.fillText(lines[i].slice(0,88),P,P+70+i*lh+22);}x.font="600 22px system-ui,Segoe UI,Arial";x.fillStyle="#c9a227";var d=location.hostname.replace("www.","");x.fillText(d,W-P-x.measureText(d).width,H-P+6);c.toBlob(function(bl){var u=URL.createObjectURL(bl),a=document.createElement("a");a.href=u;a.download=(t||"result").replace(/[^a-z0-9]+/gi,"-").toLowerCase()+"-"+d+".png";document.body.appendChild(a);a.click();setTimeout(function(){URL.revokeObjectURL(u);a.remove();},2000);},"image/png");});})();</script><script>(function(){var b=document.getElementById("yjcp");if(!b)return;var t=b.textContent;b.addEventListener("click",function(){var u=location.href.split("#")[0];function d(){b.textContent="Link copied";setTimeout(function(){b.textContent=t;},1800);}if(navigator.clipboard&&navigator.clipboard.writeText){navigator.clipboard.writeText(u).then(d,function(){prompt("",u);});}else{prompt("",u);}});})();</script><div class="yj-home-find"><div class="yj-lgbar"><a href="/" class="yj-lg on">EN</a><a href="/de/" class="yj-lg">DE</a><a href="/ja/" class="yj-lg">JA</a><a href="/es/" class="yj-lg">ES</a><a href="/pt/" class="yj-lg">PT</a></div><section class="yj-find"><h2>Find a tool</h2><input id="yjq" type="search" autocomplete="off" placeholder="Type a product name, format or task"><div id="yjr"></div></section><style>.yj-lgbar{position:absolute;top:14px;right:18px;display:flex;gap:6px;z-index:60}.yj-lg{font:600 12px/1 system-ui,sans-serif;padding:6px 9px;border-radius:4px;text-decoration:none;color:#8b96a3;border:1px solid rgba(140,150,165,.28)}.yj-lg:hover{color:#e8eaed;border-color:rgba(160,175,195,.6)}.yj-lg.on{color:#0e1116;background:#cfd6de;border-color:#cfd6de}.yj-find{max-width:760px;margin:34px auto 8px;padding:0 20px}.yj-find h2{font:600 20px/1.3 system-ui,sans-serif;margin:0 0 10px}#yjq{width:100%;box-sizing:border-box;padding:13px 15px;font:400 15.5px system-ui,sans-serif;border:1px solid rgba(140,150,165,.34);border-radius:8px;background:rgba(255,255,255,.04);color:inherit}#yjq:focus{outline:none;border-color:#7FD1C4}#yjr{margin-top:10px;display:flex;flex-direction:column;gap:6px}#yjr a{display:flex;justify-content:space-between;gap:12px;padding:11px 14px;border:1px solid rgba(140,150,165,.22);border-radius:6px;text-decoration:none;font:400 14.5px/1.4 system-ui,sans-serif;color:inherit}#yjr a:hover{border-color:#7FD1C4}#yjr .pr{font:600 13px system-ui,sans-serif;color:#5fbf9a;white-space:nowrap}</style><script>(function(){var q=document.getElementById("yjq"),r=document.getElementById("yjr"),D=null;function load(){if(D)return Promise.resolve(D);return fetch("/search-index.json").then(function(x){return x.json();}).then(function(j){D=j;return j;}).catch(function(){D=[];return D;});}function esc(t){return String(t).replace(/[&<>"]/g,function(c){return {"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;"}[c];});}function run(){var v=q.value.trim().toLowerCase();if(v.length<2){r.innerHTML="";return;}load().then(function(j){var w=v.split(/\s+/),o=[];for(var i=0;i<j.length&&o.length<12;i++){var t=j[i].t.toLowerCase();var ok=true;for(var k=0;k<w.length;k++){if(t.indexOf(w[k])<0){ok=false;break;}}if(ok)o.push(j[i]);}r.innerHTML=o.length?o.map(function(x){return "<a href=\""+esc(x.u)+"\">"+"<span>"+esc(x.t)+"</span>"+(x.p?"<span class=\"pr\">$"+x.p+"</span>":"")+"</a>";}).join(""):"";});}q.addEventListener("input",run);q.addEventListener("focus",load);})();</script></div>


<script data-yj="yj-view-beacon">(function(){try{var p=location.pathname;var k='yjv:'+p;if(sessionStorage.getItem(k))return;sessionStorage.setItem(k,'1');fetch('/api/ev',{method:'POST',keepalive:true,headers:{'Content-Type':'application/json'},body:JSON.stringify({path:p,lang:"en",ref:(document.referrer||''),src:(function(){try{return (new URLSearchParams(location.search).get('ref')||'').replace(/[^a-z_]/g,'').slice(0,12)}catch(e){return ''}})()})}).catch(function(){});}catch(e){}})();</script>

<script data-yj="yj-use-beacon">(function(){try{var o=document.getElementById('out');if(!o)return;var p=location.pathname,k='yju:'+p,sent=false;function fire(){if(sent||sessionStorage.getItem(k))return;if(!(o.textContent||'').replace(/\s+/g,'').length)return;sent=true;sessionStorage.setItem(k,'1');fetch('/api/ev',{method:'POST',keepalive:true,headers:{'Content-Type':'application/json'},body:JSON.stringify({path:p,lang:"en",t:'use',src:(function(){try{return (new URLSearchParams(location.search).get('ref')||'').replace(/[^a-z_]/g,'').slice(0,12)}catch(e){return ''}})()})}).catch(function(){});}var mo=new MutationObserver(function(){fire();if(sent)mo.disconnect();});mo.observe(o,{childList:true,characterData:true,subtree:true});}catch(e){}})();</script>
<section data-yj="yj-facts-v1" style="max-width:920px;margin:48px auto 0;padding:0 20px;font-family:system-ui,sans-serif"><style>.yj-article p{font:400 15.5px/1.7 system-ui,sans-serif;color:#26313b;margin:0 0 12px;max-width:72ch}.yj-article h2,.yj-article h3,.yj-article h4{font:600 17px/1.35 system-ui,sans-serif;color:#1b1f24;margin:22px 0 8px}.yj-article table{border-collapse:collapse;margin:10px 0 16px;font:14px/1.45 system-ui,sans-serif}.yj-article th,.yj-article td{border:1px solid #e2e6ea;padding:6px 10px;text-align:left}.yj-article th{background:#f4f6f8}.yj-article pre{background:#0f1720;color:#e6edf3;padding:12px 14px;border-radius:8px;overflow:auto;font:13px/1.5 ui-monospace,Menlo,monospace}.yj-article code{font:13px ui-monospace,Menlo,monospace;background:#f1f3f5;padding:1px 4px;border-radius:3px}.yj-article pre code{background:none;padding:0}.yj-article ul,.yj-article ol{font:15px/1.6 system-ui,sans-serif;color:#26313b}</style><p style="font:400 13px/1.5 system-ui,sans-serif;color:#6b7680;margin:0 0 14px"><time datetime="2026-09-08">Updated 2026-09-08</time> · ReadyStack</p><script type="application/ld+json">{"@context":"https://schema.org","@type":"WebPage","dateModified":"2026-09-08","author":{"@type":"Organization","name":"ReadyStack"}}</script><h2 style="font:600 21px/1.3 system-ui,sans-serif;margin:0 0 6px;color:#1b1f24">Worked example</h2><p style="font:400 14.5px/1.5 system-ui,sans-serif;margin:0 0 16px;color:#5b6570">Real numbers from this tool, line by line.</p><div class="yj-article"><p><img src="https://getreadystack.com/img/promo/sku10429_result_card.jpg" alt="The secret GitHub&#x27;s free scanner will never flag for you" loading="lazy" style="max-width:100%;border-radius:6px"></p>
<p>There are two kinds of credential in a repository, and only one of them gets caught.</p>
<p>The first kind is a token a cloud provider issued: a GitHub PAT, an AWS access key, a Stripe key. These have a shape. GitHub&#x27;s free secret scanning knows that shape, matches it, and tells the provider to revoke it. That system works, and it is free on public repositories.</p>
<p>The second kind is the one you typed yourself:</p>
<pre><code>Server=tcp:reporting.database.windows.net,1433;Database=reporting;User Id=svc_reader;Password=Sup3rSecret!;
TrustServerCertificate=true</code></pre>
<p>No provider issued that password. It has no shape. Nobody can revoke it for you. On GitHub&#x27;s free tier it is not a partner pattern, so nothing flags it — generic and unstructured secret detection lives inside GitHub Secret Protection, published at $19 per active committer per month, and even then it reports *after* the push has landed.</p>
<p>That second line is worse than the first, and it never gets discussed. <code>TrustServerCertificate=true</code> tells the driver to accept any certificate presented to it. The connection still says &quot;encrypted&quot;. It is encrypted to whoever is standing in the middle.</p>
<h3>The five that get through</h3>
<p>These are all generic patterns. None of them is a partner token, so none of them trips a free scanner:</p>
<pre><code>// 1. an IoT Hub device identity anyone who clones the repo can impersonate
HostName=my-hub.azure-devices.net;DeviceId=sensor-01;SharedAccessKey=aBcD...uvwx=

// 2. a cluster-admin certificate that is not tied to a person and cannot be revoked per-user
az aks get-credentials --resource-group rg --name prod --admin

// 3. a credential that travels into every proxy log and error page that copies the URL
mongodb://admin:hunter2@cluster0.example.net/db</code></pre>
<p>And in R, where the whole thing gets rendered into an HTML report and emailed:</p>
<pre><code>Sys.setenv(IOTHUB_SAS_TOKEN = &quot;SharedAccessSignature sr=...&amp;sig=...&quot;)
con &lt;- DBI::dbConnect(odbc::odbc(), password = &quot;letmein&quot;)</code></pre>
<h3>What to write instead</h3>
<p>Every one of these has a boring, correct form. The point is not that it is hard — it is that you have to remember it at 6pm on the day the build has to be green:</p>
<pre><code>var connectionString = Environment.GetEnvironmentVariable(&quot;SQL_CONNECTION_STRING&quot;)
    ?? throw new InvalidOperationException(&quot;SQL_CONNECTION_STRING is not set.&quot;);</code></pre>
<pre><code>token &lt;- Sys.getenv(&quot;IOTHUB_SAS_TOKEN&quot;)
if (!nzchar(token)) stop(&quot;IOTHUB_SAS_TOKEN is not set. Add it to .Renviron, which stays out of git.&quot;)</code></pre>
<h3>Checking it before the push, not after</h3>
<p>Connection String &amp; Secret Audit is a VS Code extension carrying 26 rules and 32 safe-replacement snippets across 8 stacks — Azure IoT Hub, SQL Server, SQLTools, AKS and Kubernetes, .NET MAUI, Java MicroProfile, R, and R Markdown or Quarto.</p>
<p>Auditing the file you have open is free and needs no key, no account, and no upload. It matches all 26 rules, prints each finding with its line number, and any of the 32 snippets drops the environment-variable form in at your cursor. That is the whole job for one file, finished.</p>
<p>What a licence adds is scale and handover: the same audit across every file in the workspace instead of one, and the findings written out as a CSV, JSON or HTML file you keep in the repo and hand to a reviewer. One-time $29, against $19 per committer per month for the hosted equivalent.</p>
<p>Nothing is sent anywhere. The rules run in your editor, on your machine, on a file that has not been pushed yet — which is the only moment any of this is still fixable.</p></div><h2 style="font:600 19px/1.3 system-ui,sans-serif;margin:30px 0 10px;color:#1b1f24">15 seconds — what it actually does</h2><video controls muted playsinline preload="none" poster="/img/promo/sku10429_result_card.jpg" style="width:100%;max-width:360px;border-radius:10px;display:block;margin:0 auto"><source src="/media/sku10429_short.mp4" type="video/mp4"></video><h2 style="font:600 21px/1.3 system-ui,sans-serif;margin:34px 0 6px;color:#1b1f24">Questions people ask</h2><details style="border-bottom:1px solid #e6e9ed;padding:10px 0"><summary style="cursor:pointer;font:600 15px/1.4 system-ui,sans-serif;color:#1b1f24">What does the Connection String &amp; Secret Audit extension actually do?</summary><p style="margin:8px 0 2px;font:400 14.5px/1.6 system-ui,sans-serif;color:#33404b">It reads the file open in VS Code and matches every line against 26 rules for hardcoded credentials: IoT Hub and Service Bus connection strings, SQL Server passwords, TrustServerCertificate=true, committed kubeconfig data, private key blocks, JWTs and credentials embedded in URLs. Each finding prints with its line number, and 32 snippets insert the environment-variable form at your cursor.</p></details><details style="border-bottom:1px solid #e6e9ed;padding:10px 0"><summary style="cursor:pointer;font:600 15px/1.4 system-ui,sans-serif;color:#1b1f24">Who is this VS Code secret audit extension for?</summary><p style="margin:8px 0 2px;font:400 14.5px/1.6 system-ui,sans-serif;color:#33404b">Developers on Azure IoT Hub, SQL Server, AKS, .NET MAUI, Java MicroProfile and R or R Markdown who work in private repositories. It is aimed at the person who pastes a working connection string to get a build green and means to take it out before pushing, and at the reviewer who has to prove none is left.</p></details><details style="border-bottom:1px solid #e6e9ed;padding:10px 0"><summary style="cursor:pointer;font:600 15px/1.4 system-ui,sans-serif;color:#1b1f24">Why is GitHub&#x27;s free secret scanning not enough?</summary><p style="margin:8px 0 2px;font:400 14.5px/1.6 system-ui,sans-serif;color:#33404b">GitHub&#x27;s free scanning covers partner patterns, meaning token formats a cloud provider issues and can revoke. A password you typed into a connection string is not one of those. Generic and unstructured secret detection sits inside GitHub Secret Protection at $19 per active committer per month, and it reports after the push, not before.</p></details><details style="border-bottom:1px solid #e6e9ed;padding:10px 0"><summary style="cursor:pointer;font:600 15px/1.4 system-ui,sans-serif;color:#1b1f24">What is free in this extension and what needs a licence?</summary><p style="margin:8px 0 2px;font:400 14.5px/1.6 system-ui,sans-serif;color:#33404b">Free covers one file end to end: the full audit of the open file or the highlighted lines against all 26 rules, all 32 replacement snippets, and the rule list. A licence widens it to scale and to handover, auditing every file in the workspace and exporting the findings as a CSV, JSON or HTML file you keep.</p></details><details style="border-bottom:1px solid #e6e9ed;padding:10px 0"><summary style="cursor:pointer;font:600 15px/1.4 system-ui,sans-serif;color:#1b1f24">How does the cost compare to a hosted secret scanner or a manual review?</summary><p style="margin:8px 0 2px;font:400 14.5px/1.6 system-ui,sans-serif;color:#33404b">GitHub Secret Protection is published at $19 per active committer per month, so a team of five is $95 every month for as long as they commit. This extension is $29 once per developer, runs locally, and sends no source code to any server. A one-hour manual credential review by a contractor typically costs more than $29.</p></details><script type="application/ld+json" data-yj="yj-faq-ld">{"@context": "https://schema.org", "@type": "FAQPage", "mainEntity": [{"@type": "Question", "name": "What does the Connection String & Secret Audit extension actually do?", "acceptedAnswer": {"@type": "Answer", "text": "It reads the file open in VS Code and matches every line against 26 rules for hardcoded credentials: IoT Hub and Service Bus connection strings, SQL Server passwords, TrustServerCertificate=true, committed kubeconfig data, private key blocks, JWTs and credentials embedded in URLs. Each finding prints with its line number, and 32 snippets insert the environment-variable form at your cursor."}}, {"@type": "Question", "name": "Who is this VS Code secret audit extension for?", "acceptedAnswer": {"@type": "Answer", "text": "Developers on Azure IoT Hub, SQL Server, AKS, .NET MAUI, Java MicroProfile and R or R Markdown who work in private repositories. It is aimed at the person who pastes a working connection string to get a build green and means to take it out before pushing, and at the reviewer who has to prove none is left."}}, {"@type": "Question", "name": "Why is GitHub's free secret scanning not enough?", "acceptedAnswer": {"@type": "Answer", "text": "GitHub's free scanning covers partner patterns, meaning token formats a cloud provider issues and can revoke. A password you typed into a connection string is not one of those. Generic and unstructured secret detection sits inside GitHub Secret Protection at $19 per active committer per month, and it reports after the push, not before."}}, {"@type": "Question", "name": "What is free in this extension and what needs a licence?", "acceptedAnswer": {"@type": "Answer", "text": "Free covers one file end to end: the full audit of the open file or the highlighted lines against all 26 rules, all 32 replacement snippets, and the rule list. A licence widens it to scale and to handover, auditing every file in the workspace and exporting the findings as a CSV, JSON or HTML file you keep."}}, {"@type": "Question", "name": "How does the cost compare to a hosted secret scanner or a manual review?", "acceptedAnswer": {"@type": "Answer", "text": "GitHub Secret Protection is published at $19 per active committer per month, so a team of five is $95 every month for as long as they commit. This extension is $29 once per developer, runs locally, and sends no source code to any server. A one-hour manual credential review by a contractor typically costs more than $29."}}]}</script><div id="yj-ask" style="margin:36px 0 0;padding:18px 18px 16px;border:1px solid #e2e6ea;border-radius:10px;background:#fbfbfc"><h2 style="font:600 19px/1.3 system-ui,sans-serif;margin:0 0 4px;color:#1b1f24">Ask about this tool</h2><p style="font:400 13.5px/1.5 system-ui,sans-serif;margin:0 0 12px;color:#5b6570">One question, answered by the person who built it. Your email only if you want the answer sent.</p><form onsubmit="return yjAsk(event)" style="display:grid;gap:8px"><textarea name="question" required minlength="10" maxlength="2000" rows="3" placeholder="Your question" style="font:14px/1.5 system-ui,sans-serif;padding:10px;border:1px solid #cfd6dd;border-radius:6px"></textarea><div style="display:flex;gap:8px;flex-wrap:wrap"><input type="email" name="email" placeholder="Email (optional)" style="flex:1;min-width:200px;font:14px system-ui,sans-serif;padding:9px 10px;border:1px solid #cfd6dd;border-radius:6px"><button type="submit" style="font:600 14px system-ui,sans-serif;padding:9px 18px;border:0;border-radius:6px;background:#1b1f24;color:#fff;cursor:pointer">Send</button></div><p id="yj-ask-msg" style="font:13px system-ui,sans-serif;margin:2px 0 0;color:#0a6238;min-height:1em"></p></form><script>function yjAsk(e){e.preventDefault();var f=e.target,m=document.getElementById("yj-ask-msg");m.style.color="#0a6238";fetch(location.origin+"/api/ask",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({sku:10429,slug:"connection-string-secret-audit",lang:"en",question:f.question.value,email:f.email.value,page:location.pathname})}).then(function(r){if(!r.ok)throw 0;m.textContent="Thanks \u2014 noted. Answers land on this page and, if you left an email, in your inbox.";f.question.value="";}).catch(function(){m.style.color="#a8551f";m.textContent="Could not send. Please try again in a minute.";});return false;}</script></div></section><section class="yj-related" style="max-width:920px;margin:56px auto 40px;padding:0 20px"><h2 style="font:600 21px/1.3 system-ui,sans-serif;margin:0 0 6px;color:#1b1f24">Same job, next tool</h2><p style="font:400 14.5px/1.5 system-ui,sans-serif;margin:0 0 20px;color:#5b6570">Free in the browser. The full version is a one-time licence.</p><div style="display:grid;grid-template-columns:repeat(auto-fill,minmax(250px,1fr));gap:14px"><a class="yj-rel-c" href="https://getreadystack.com/tools/autohotkey-toml-devicetree-snippets"><span class="yj-rel-t">AutoHotkey v2, TOML and DeviceTree checks for VS Code</span><span class="yj-rel-p">$29</span></a><a class="yj-rel-c" href="https://getreadystack.com/tools/bulk-sender-lint"><span class="yj-rel-t">Bulk Sender Lint - the Gmail, Yahoo and Outlook.com rules, checked in your mai</span><span class="yj-rel-p">$29</span></a><a class="yj-rel-c" href="https://getreadystack.com/tools/devicetree-config-language-pack"><span class="yj-rel-t">DeviceTree Config Audit: 23 dtc-Style Rules, 50 Snippets</span><span class="yj-rel-p">$29</span></a><a class="yj-rel-c" href="https://getreadystack.com/tools/robots-txt-ai-crawler-audit"><span class="yj-rel-t">AI Crawler Rules - robots.txt Audit for AI Search</span><span class="yj-rel-p">$29</span></a><a class="yj-rel-c" href="https://getreadystack.com/tools/config-dsl-lint-snippet-pack"><span class="yj-rel-t">Config &amp; DSL Lint + Snippets — 9 Sets</span><span class="yj-rel-p">$29</span></a><a class="yj-rel-c" href="https://getreadystack.com/tools/coverage-gate-lint"><span class="yj-rel-t">Coverage Gate Lint</span><span class="yj-rel-p">$29</span></a></div><style>.yj-rel-c{display:flex;flex-direction:column;gap:8px;padding:15px 16px;border:1px solid #e2e6ea;border-radius:6px;text-decoration:none;background:#fff}.yj-rel-c:hover{border-color:#b9c2cb;background:#fafbfc}.yj-rel-t{font:500 14.5px/1.42 system-ui,sans-serif;color:#1b1f24}.yj-rel-p{font:600 13px system-ui,sans-serif;color:#0a6238}</style></section>