Upload index.html with huggingface_hub
Browse files- index.html +23 -7
index.html
CHANGED
|
@@ -2,7 +2,6 @@
|
|
| 2 |
<meta name="viewport" content="width=device-width,initial-scale=1">
|
| 3 |
<title>Firmware Release Gate for sdkconfig and prj.conf</title>
|
| 4 |
<meta name="description" content="Finds the build-config lines that ship an ESP-IDF or Zephyr device with secure boot off, a debug port open, unsigned images or plaintext OTA.">
|
| 5 |
-
<script defer data-auto-init src="https://cdn.jsdelivr.net/npm/@polar-sh/checkout@latest/dist/embed.global.js"></script>
|
| 6 |
<style>
|
| 7 |
:root{color-scheme:light dark}
|
| 8 |
body{margin:0;font:16px/1.6 system-ui,-apple-system,"Segoe UI",sans-serif;
|
|
@@ -42,7 +41,7 @@ CONFIG_PARTITION_TABLE_TWO_OTA=y
|
|
| 42 |
</textarea>
|
| 43 |
<button id="go">Audit this config</button>
|
| 44 |
<div id="out"></div>
|
| 45 |
-
<div class="next"><h2>In the full version</h2><ul><li>Audit every config in the workspace</li><li>Export the audit report as CSV, JSON or HTML</li><li>Machine-readable JSON for CI</li><li><a href="https://
|
| 46 |
</div>
|
| 47 |
<script>
|
| 48 |
var RULES=[{"pattern": "^\\s*#\\s*CONFIG_SECURE_BOOT is not set", "flags": "", "sev": "error", "message": "Secure boot is off: the ROM will boot any image written to flash. Set CONFIG_SECURE_BOOT=y and choose the Secure Boot V2 scheme before the release build."}, {"pattern": "^\\s*CONFIG_SECURE_FLASH_ENCRYPTION_MODE_DEVELOPMENT=y", "flags": "", "sev": "error", "message": "Flash encryption is in Development mode: the unit still accepts re-flashing and the key stays readable. Production units need CONFIG_SECURE_FLASH_ENCRYPTION_MODE_RELEASE=y."}, {"pattern": "^\\s*#\\s*CONFIG_SECURE_FLASH_ENC_ENABLED is not set", "flags": "", "sev": "error", "message": "Flash encryption is off: firmware, certificates and NVS can be read straight off the flash chip. Set CONFIG_SECURE_FLASH_ENC_ENABLED=y."}, {"pattern": "^\\s*CONFIG_SECURE_BOOT_ALLOW_[A-Z0-9_]+=y", "flags": "", "sev": "error", "message": "A secure-boot escape hatch is enabled, so JTAG, the ROM console or the UART bootloader stays reachable on a locked unit. Remove every CONFIG_SECURE_BOOT_ALLOW_* line from the release config."}, {"pattern": "^\\s*CONFIG_ESP_TLS_SKIP_SERVER_CERT_VERIFY=y", "flags": "", "sev": "error", "message": "TLS server certificates are not verified: anything on the path can terminate your OTA and telemetry sessions. Remove this line and pin a CA bundle instead."}, {"pattern": "^\\s*CONFIG_ESP_TLS_INSECURE=y", "flags": "", "sev": "error", "message": "esp-tls insecure mode is compiled in, which lets any call site skip certificate checks at runtime. Remove CONFIG_ESP_TLS_INSECURE from the release config."}, {"pattern": "^\\s*CONFIG_ESP_HTTPS_OTA_ALLOW_HTTP=y", "flags": "", "sev": "error", "message": "OTA is allowed to fall back to plain HTTP, so whoever sits on the path chooses the next firmware image. Remove CONFIG_ESP_HTTPS_OTA_ALLOW_HTTP."}, {"pattern": "^\\s*CONFIG_[A-Z0-9_]*(?:URL|URI|ENDPOINT|SERVER|HOST)[A-Z0-9_]*=\"http://", "flags": "", "sev": "error", "message": "A plaintext http:// endpoint is baked into the build config and ships inside the image. Move it to https:// before the release build."}, {"pattern": "^\\s*CONFIG_[A-Z0-9_]*(?:PASSWORD|PASSPHRASE|PSK|SECRET|TOKEN|API_?KEY)[A-Z0-9_]*=\"[^\"]+\"", "flags": "", "sev": "error", "message": "A credential is hard-coded in the build config: it ships inside every image and it is already in your git history. Read it from NVS or from a provisioning step."}, {"pattern": "^\\s*CONFIG_[A-Z0-9_]*PANIC[A-Z0-9_]*GDBSTUB=y", "flags": "", "sev": "error", "message": "The panic handler drops into a GDB stub, so a crash hands an attacker a debugger on the device. Ship the print-and-reboot panic handler instead."}, {"pattern": "^\\s*CONFIG_(?:BOOTLOADER_)?LOG_(?:DEFAULT_)?LEVEL=[45]", "flags": "", "sev": "warn", "message": "Log level is Debug or Verbose, so boot detail and buffer contents leave a shipped unit over the UART. Use level 1 (error) or 2 (warn) for release."}, {"pattern": "^\\s*#\\s*CONFIG_NVS_ENCRYPTION is not set", "flags": "", "sev": "warn", "message": "NVS encryption is off: Wi-Fi credentials and tokens sit in cleartext in the NVS partition. Set CONFIG_NVS_ENCRYPTION=y."}, {"pattern": "^\\s*CONFIG_BOOT_SIGNATURE_TYPE_NONE=y", "flags": "", "sev": "error", "message": "MCUboot is set to accept unsigned images, so anything written to the update slot will boot. Choose an ECDSA or RSA signature type."}, {"pattern": "^\\s*#\\s*CONFIG_BOOT_VALIDATE_SLOT0 is not set", "flags": "", "sev": "error", "message": "MCUboot does not validate the primary slot at boot, so a tampered image is never caught after it is installed. Set CONFIG_BOOT_VALIDATE_SLOT0=y."}, {"pattern": "^\\s*#\\s*CONFIG_MCUBOOT_DOWNGRADE_PREVENTION is not set", "flags": "", "sev": "warn", "message": "Downgrade prevention is off: a signed but withdrawn image can be rolled back onto the device. Set CONFIG_MCUBOOT_DOWNGRADE_PREVENTION=y."}, {"pattern": "^\\s*#\\s*CONFIG_HW_STACK_PROTECTION is not set", "flags": "", "sev": "warn", "message": "Hardware stack protection is off, so a stack overflow becomes silent memory corruption instead of a fault. Set CONFIG_HW_STACK_PROTECTION=y."}, {"pattern": "^\\s*CONFIG_SHELL=y", "flags": "", "sev": "warn", "message": "An interactive shell is built in, so on a shipped unit the serial console is a command prompt. Keep CONFIG_SHELL in the debug overlay only."}, {"pattern": "^\\s*CONFIG_(?:DEBUG|DEBUG_OPTIMIZATIONS|COMPILER_OPTIMIZATION_(?:NONE|DEBUG))=y", "flags": "", "sev": "info", "message": "This is a debug build configuration; a release unit should be built at the size or performance optimisation level."}];
|
|
@@ -64,16 +63,33 @@ document.getElementById('go').click();
|
|
| 64 |
</script>
|
| 65 |
</html>
|
| 66 |
|
| 67 |
-
<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 one email when this rule changes</b><div style="opacity:.78;margin:.35rem 0 .8rem">We watch the regulation and vendor sources behind Firmware Release Gate for sdkconfig and prj.conf every day. When a rule changes, you get a single email with what changed and the updated check. 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">Notify me</button></div><div id="yjao" hidden style="margin-top:.6rem;color:#0f7b3f">You're on the list. One email when it changes.</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:"firmware-release-gate",lang:"en",source:"rule_alert"})}).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></section>
|
| 68 |
-
|
| 69 |
|
| 70 |
<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://marketplace.visualstudio.com/items?itemName=ReadyStack.firmware-release-gate" rel="noopener" data-yj-install-door="mp" onclick="try{navigator.sendBeacon('/api/ev',new Blob([JSON.stringify({t:'install',slug:'firmware-release-gate',src:'mp',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">VS Code Marketplace</a><a href="https://open-vsx.org/extension/readystack/firmware-release-gate" rel="noopener" data-yj-install-door="ovsx" onclick="try{navigator.sendBeacon('/api/ev',new Blob([JSON.stringify({t:'install',slug:'firmware-release-gate',src:'ovsx',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">Open VSX (Cursor, VSCodium)</a><a href="https://www.npmjs.com/package/@readystack/firmware-release-gate" rel="noopener" data-yj-install-door="npm" onclick="try{navigator.sendBeacon('/api/ev',new Blob([JSON.stringify({t:'install',slug:'firmware-release-gate',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/firmware-release-gate" rel="noopener" data-yj-install-door="mcp" onclick="try{navigator.sendBeacon('/api/ev',new Blob([JSON.stringify({t:'install',slug:'firmware-release-gate',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/firmware-release-gate" rel="noopener" data-yj-install-door="docker" onclick="try{navigator.sendBeacon('/api/ev',new Blob([JSON.stringify({t:'install',slug:'firmware-release-gate',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">ext install ReadyStack.firmware-release-gate
|
| 71 |
npx @readystack/firmware-release-gate <file>
|
| 72 |
-
npx @readystack/firmware-release-gate --mcp</pre><p style="margin:.6rem 0 0;font-size:.92rem;color:#41505f"><a href="https://
|
| 73 |
-
<section data-yj-
|
| 74 |
-
<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><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 Firmware Release Gate actually check?</summary><p style="margin:8px 0 2px;font:400 14.5px/1.6 system-ui,sans-serif;color:#33404b">It reads an ESP-IDF sdkconfig, a sdkconfig.defaults or a Zephyr prj.conf and reports the lines that a shipped unit should not carry: secure boot off, flash encryption in Development mode, a secure-boot escape hatch, unsigned MCUboot images, skipped TLS verification, plaintext http:// endpoints and hard-coded credentials. Each finding names the line number and the setting a release build should carry instead.</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 for?</summary><p style="margin:8px 0 2px;font:400 14.5px/1.6 system-ui,sans-serif;color:#33404b">Embedded firmware engineers who own the release build of an ESP32 or Zephyr product, and the one person on a small hardware team who signs off that a batch may be flashed. If you build with idf.py or west and the config lives in git, this reads the same files your build reads.</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 will a chatbot or a free checker not do this?</summary><p style="margin:8px 0 2px;font:400 14.5px/1.6 system-ui,sans-serif;color:#33404b">A chatbot cannot see your sdkconfig, and pasting a generated config into one gives you advice about symbols that may not exist in your IDF version. The free Kconfig hardening checkers in this space target the Linux kernel, not ESP-IDF or Zephyr and MCUboot, so the symbols that decide whether your device boots unsigned images are not in their rule sets.</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 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 audits the config file you have open, the whole file, with every finding and its remedy, and it never asks for a key. A licence adds the jobs that start when one file is not enough: auditing every config in the repository, exporting the report file you keep with the release, and a JSON output that fails the build in CI.</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 would this cost otherwise?</summary><p style="margin:8px 0 2px;font:400 14.5px/1.6 system-ui,sans-serif;color:#33404b">An outside firmware-only security review starts around $6,000, and a full IoT device assessment runs roughly $10,000 to $50,000. Those are worth paying for, but not to be told that flash encryption was left in Development mode. This is $29 once, so the review you pay for starts past the config layer.</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 does this matter now rather than at the next release?</summary><p style="margin:8px 0 2px;font:400 14.5px/1.6 system-ui,sans-serif;color:#33404b">From 11 September 2026 the EU Cyber Resilience Act requires a manufacturer to report an actively exploited vulnerability in a product with digital elements: an early warning to ENISA and the national CSIRT within 24 hours and a full notification within 72 hours. A unit that boots unsigned images or ships a hard-coded credential is not a bug you patch quietly, and units in the field cannot be re-configured.</p></details><script type="application/ld+json" data-yj="yj-faq-ld">{"@context": "https://schema.org", "@type": "FAQPage", "mainEntity": [{"@type": "Question", "name": "What does Firmware Release Gate actually check?", "acceptedAnswer": {"@type": "Answer", "text": "It reads an ESP-IDF sdkconfig, a sdkconfig.defaults or a Zephyr prj.conf and reports the lines that a shipped unit should not carry: secure boot off, flash encryption in Development mode, a secure-boot escape hatch, unsigned MCUboot images, skipped TLS verification, plaintext http:// endpoints and hard-coded credentials. Each finding names the line number and the setting a release build should carry instead."}}, {"@type": "Question", "name": "Who is this for?", "acceptedAnswer": {"@type": "Answer", "text": "Embedded firmware engineers who own the release build of an ESP32 or Zephyr product, and the one person on a small hardware team who signs off that a batch may be flashed. If you build with idf.py or west and the config lives in git, this reads the same files your build reads."}}, {"@type": "Question", "name": "Why will a chatbot or a free checker not do this?", "acceptedAnswer": {"@type": "Answer", "text": "A chatbot cannot see your sdkconfig, and pasting a generated config into one gives you advice about symbols that may not exist in your IDF version. The free Kconfig hardening checkers in this space target the Linux kernel, not ESP-IDF or Zephyr and MCUboot, so the symbols that decide whether your device boots unsigned images are not in their rule sets."}}, {"@type": "Question", "name": "What is free and what needs a licence?", "acceptedAnswer": {"@type": "Answer", "text": "Free audits the config file you have open, the whole file, with every finding and its remedy, and it never asks for a key. A licence adds the jobs that start when one file is not enough: auditing every config in the repository, exporting the report file you keep with the release, and a JSON output that fails the build in CI."}}, {"@type": "Question", "name": "What would this cost otherwise?", "acceptedAnswer": {"@type": "Answer", "text": "An outside firmware-only security review starts around $6,000, and a full IoT device assessment runs roughly $10,000 to $50,000. Those are worth paying for, but not to be told that flash encryption was left in Development mode. This is $29 once, so the review you pay for starts past the config layer."}}, {"@type": "Question", "name": "Why does this matter now rather than at the next release?", "acceptedAnswer": {"@type": "Answer", "text": "From 11 September 2026 the EU Cyber Resilience Act requires a manufacturer to report an actively exploited vulnerability in a product with digital elements: an early warning to ENISA and the national CSIRT within 24 hours and a full notification within 72 hours. A unit that boots unsigned images or ships a hard-coded credential is not a bug you patch quietly, and units in the field cannot be re-configured."}}]}</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:0,slug:"firmware-release-gate",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, 7-day refund.</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/lead-magnet-ebook-template"><span class="yj-rel-t">Lead Magnet Ebook Template - 20 Fill-In Templates to Build and Ship Your Email</span><span class="yj-rel-p">$49</span></a><a class="yj-rel-c" href="https://getreadystack.com/tools/webflow-restaurant-template"><span class="yj-rel-t">Webflow Restaurant Template — delivered as self-contained HTML you own: 26 pag</span><span class="yj-rel-p">$49</span></a><a class="yj-rel-c" href="https://getreadystack.com/tools/config-dsl-lint-snippet-pack"><span class="yj-rel-t">Config & DSL Lint + Snippets — 9 Sets</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/gtags-workspace-config-kit"><span class="yj-rel-t">GNU GLOBAL (gtags) Workspace Setup Kit</span><span class="yj-rel-p">$29</span></a><a class="yj-rel-c" href="https://getreadystack.com/tools/gnu-global-cpp-vscode-config-pack"><span class="yj-rel-t">GNU Global C/C++ .vscode Config Pack</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><!--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 {"&":"&","<":"<",">":">",'"':"""}[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>
|
|
|
|
|
|
|
| 75 |
|
| 76 |
|
| 77 |
<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>
|
| 78 |
|
| 79 |
<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>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2 |
<meta name="viewport" content="width=device-width,initial-scale=1">
|
| 3 |
<title>Firmware Release Gate for sdkconfig and prj.conf</title>
|
| 4 |
<meta name="description" content="Finds the build-config lines that ship an ESP-IDF or Zephyr device with secure boot off, a debug port open, unsigned images or plaintext OTA.">
|
|
|
|
| 5 |
<style>
|
| 6 |
:root{color-scheme:light dark}
|
| 7 |
body{margin:0;font:16px/1.6 system-ui,-apple-system,"Segoe UI",sans-serif;
|
|
|
|
| 41 |
</textarea>
|
| 42 |
<button id="go">Audit this config</button>
|
| 43 |
<div id="out"></div>
|
| 44 |
+
<div class="next"><h2>In the full version</h2><ul><li>Audit every config in the workspace</li><li>Export the audit report as CSV, JSON or HTML</li><li>Machine-readable JSON for CI</li><li><a href="https://getreadystack.com/api/buy/cl/polar_cl_cmmWDH5sYqYlHlEAy4aCkF8gPdT40c3FhYupJ1VFP22">Get the full version - $29</a></li></ul></div>
|
| 45 |
</div>
|
| 46 |
<script>
|
| 47 |
var RULES=[{"pattern": "^\\s*#\\s*CONFIG_SECURE_BOOT is not set", "flags": "", "sev": "error", "message": "Secure boot is off: the ROM will boot any image written to flash. Set CONFIG_SECURE_BOOT=y and choose the Secure Boot V2 scheme before the release build."}, {"pattern": "^\\s*CONFIG_SECURE_FLASH_ENCRYPTION_MODE_DEVELOPMENT=y", "flags": "", "sev": "error", "message": "Flash encryption is in Development mode: the unit still accepts re-flashing and the key stays readable. Production units need CONFIG_SECURE_FLASH_ENCRYPTION_MODE_RELEASE=y."}, {"pattern": "^\\s*#\\s*CONFIG_SECURE_FLASH_ENC_ENABLED is not set", "flags": "", "sev": "error", "message": "Flash encryption is off: firmware, certificates and NVS can be read straight off the flash chip. Set CONFIG_SECURE_FLASH_ENC_ENABLED=y."}, {"pattern": "^\\s*CONFIG_SECURE_BOOT_ALLOW_[A-Z0-9_]+=y", "flags": "", "sev": "error", "message": "A secure-boot escape hatch is enabled, so JTAG, the ROM console or the UART bootloader stays reachable on a locked unit. Remove every CONFIG_SECURE_BOOT_ALLOW_* line from the release config."}, {"pattern": "^\\s*CONFIG_ESP_TLS_SKIP_SERVER_CERT_VERIFY=y", "flags": "", "sev": "error", "message": "TLS server certificates are not verified: anything on the path can terminate your OTA and telemetry sessions. Remove this line and pin a CA bundle instead."}, {"pattern": "^\\s*CONFIG_ESP_TLS_INSECURE=y", "flags": "", "sev": "error", "message": "esp-tls insecure mode is compiled in, which lets any call site skip certificate checks at runtime. Remove CONFIG_ESP_TLS_INSECURE from the release config."}, {"pattern": "^\\s*CONFIG_ESP_HTTPS_OTA_ALLOW_HTTP=y", "flags": "", "sev": "error", "message": "OTA is allowed to fall back to plain HTTP, so whoever sits on the path chooses the next firmware image. Remove CONFIG_ESP_HTTPS_OTA_ALLOW_HTTP."}, {"pattern": "^\\s*CONFIG_[A-Z0-9_]*(?:URL|URI|ENDPOINT|SERVER|HOST)[A-Z0-9_]*=\"http://", "flags": "", "sev": "error", "message": "A plaintext http:// endpoint is baked into the build config and ships inside the image. Move it to https:// before the release build."}, {"pattern": "^\\s*CONFIG_[A-Z0-9_]*(?:PASSWORD|PASSPHRASE|PSK|SECRET|TOKEN|API_?KEY)[A-Z0-9_]*=\"[^\"]+\"", "flags": "", "sev": "error", "message": "A credential is hard-coded in the build config: it ships inside every image and it is already in your git history. Read it from NVS or from a provisioning step."}, {"pattern": "^\\s*CONFIG_[A-Z0-9_]*PANIC[A-Z0-9_]*GDBSTUB=y", "flags": "", "sev": "error", "message": "The panic handler drops into a GDB stub, so a crash hands an attacker a debugger on the device. Ship the print-and-reboot panic handler instead."}, {"pattern": "^\\s*CONFIG_(?:BOOTLOADER_)?LOG_(?:DEFAULT_)?LEVEL=[45]", "flags": "", "sev": "warn", "message": "Log level is Debug or Verbose, so boot detail and buffer contents leave a shipped unit over the UART. Use level 1 (error) or 2 (warn) for release."}, {"pattern": "^\\s*#\\s*CONFIG_NVS_ENCRYPTION is not set", "flags": "", "sev": "warn", "message": "NVS encryption is off: Wi-Fi credentials and tokens sit in cleartext in the NVS partition. Set CONFIG_NVS_ENCRYPTION=y."}, {"pattern": "^\\s*CONFIG_BOOT_SIGNATURE_TYPE_NONE=y", "flags": "", "sev": "error", "message": "MCUboot is set to accept unsigned images, so anything written to the update slot will boot. Choose an ECDSA or RSA signature type."}, {"pattern": "^\\s*#\\s*CONFIG_BOOT_VALIDATE_SLOT0 is not set", "flags": "", "sev": "error", "message": "MCUboot does not validate the primary slot at boot, so a tampered image is never caught after it is installed. Set CONFIG_BOOT_VALIDATE_SLOT0=y."}, {"pattern": "^\\s*#\\s*CONFIG_MCUBOOT_DOWNGRADE_PREVENTION is not set", "flags": "", "sev": "warn", "message": "Downgrade prevention is off: a signed but withdrawn image can be rolled back onto the device. Set CONFIG_MCUBOOT_DOWNGRADE_PREVENTION=y."}, {"pattern": "^\\s*#\\s*CONFIG_HW_STACK_PROTECTION is not set", "flags": "", "sev": "warn", "message": "Hardware stack protection is off, so a stack overflow becomes silent memory corruption instead of a fault. Set CONFIG_HW_STACK_PROTECTION=y."}, {"pattern": "^\\s*CONFIG_SHELL=y", "flags": "", "sev": "warn", "message": "An interactive shell is built in, so on a shipped unit the serial console is a command prompt. Keep CONFIG_SHELL in the debug overlay only."}, {"pattern": "^\\s*CONFIG_(?:DEBUG|DEBUG_OPTIMIZATIONS|COMPILER_OPTIMIZATION_(?:NONE|DEBUG))=y", "flags": "", "sev": "info", "message": "This is a debug build configuration; a release unit should be built at the size or performance optimisation level."}];
|
|
|
|
| 63 |
</script>
|
| 64 |
</html>
|
| 65 |
|
|
|
|
|
|
|
| 66 |
|
| 67 |
<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://marketplace.visualstudio.com/items?itemName=ReadyStack.firmware-release-gate" rel="noopener" data-yj-install-door="mp" onclick="try{navigator.sendBeacon('/api/ev',new Blob([JSON.stringify({t:'install',slug:'firmware-release-gate',src:'mp',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">VS Code Marketplace</a><a href="https://open-vsx.org/extension/readystack/firmware-release-gate" rel="noopener" data-yj-install-door="ovsx" onclick="try{navigator.sendBeacon('/api/ev',new Blob([JSON.stringify({t:'install',slug:'firmware-release-gate',src:'ovsx',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">Open VSX (Cursor, VSCodium)</a><a href="https://www.npmjs.com/package/@readystack/firmware-release-gate" rel="noopener" data-yj-install-door="npm" onclick="try{navigator.sendBeacon('/api/ev',new Blob([JSON.stringify({t:'install',slug:'firmware-release-gate',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/firmware-release-gate" rel="noopener" data-yj-install-door="mcp" onclick="try{navigator.sendBeacon('/api/ev',new Blob([JSON.stringify({t:'install',slug:'firmware-release-gate',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/firmware-release-gate" rel="noopener" data-yj-install-door="docker" onclick="try{navigator.sendBeacon('/api/ev',new Blob([JSON.stringify({t:'install',slug:'firmware-release-gate',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">ext install ReadyStack.firmware-release-gate
|
| 68 |
npx @readystack/firmware-release-gate <file>
|
| 69 |
+
npx @readystack/firmware-release-gate --mcp</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>
|
| 70 |
+
<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 18 rules Firmware Release Gate for sdkconfig and prj.conf 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:"firmware-release-gate",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>
|
| 71 |
+
|
| 72 |
+
<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">Finds the build-config lines that ship an ESP-IDF or Zephyr device with secure boot off, a debug port open, unsigned images or plaintext OTA.</p><p style="margin:0 0 1rem;color:#5b6b7c;font-size:.94rem">An outside firmware-only security review starts around $6,000 and a full IoT device assessment runs $10,000 to $50,000; this is the config pass you run before you pay for one.</p><a href="https://getreadystack.com/api/buy/cl/polar_cl_cmmWDH5sYqYlHlEAy4aCkF8gPdT40c3FhYupJ1VFP22" 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>
|
| 73 |
+
<!--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 {"&":"&","<":"<",">":">",'"':"""}[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>
|
| 74 |
|
| 75 |
|
| 76 |
<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>
|
| 77 |
|
| 78 |
<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>
|
| 79 |
+
<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-10">Updated 2026-09-10</time> · ReadyStack</p><script type="application/ld+json">{"@context":"https://schema.org","@type":"WebPage","dateModified":"2026-09-10","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/sku33021_result_card.jpg" alt="Five sdkconfig lines that ship an ESP32 device unlocked" loading="lazy" style="max-width:100%;border-radius:6px"></p>
|
| 80 |
+
<p>Five findings land on the nine-line sdkconfig below - the release configuration of an ESP32-S3 gateway that a hardware team in Germany was three days from flashing into a production batch.</p>
|
| 81 |
+
<pre><code>sdkconfig:3 # CONFIG_SECURE_BOOT is not set
|
| 82 |
+
-> secure boot off: the ROM boots any image written to flash
|
| 83 |
+
sdkconfig:4 CONFIG_SECURE_FLASH_ENCRYPTION_MODE_DEVELOPMENT=y
|
| 84 |
+
-> Development mode: still re-flashable, key still readable
|
| 85 |
+
sdkconfig:5 CONFIG_ESP_TLS_SKIP_SERVER_CERT_VERIFY=y
|
| 86 |
+
-> certificates unverified: anything on the path terminates the OTA
|
| 87 |
+
sdkconfig:6 CONFIG_OTA_UPDATE_URL="http://updates.example.net/fw.bin"
|
| 88 |
+
-> the update is served in the clear
|
| 89 |
+
sdkconfig:7 CONFIG_EXAMPLE_WIFI_PASSWORD="factory-default"
|
| 90 |
+
-> the credential ships inside every image, and it is in git</code></pre>
|
| 91 |
+
<p>None of those five lines is a bug. Every one of them is a setting someone turned on deliberately, on a Tuesday, to get a board to boot - and then never turned back off. That is the shape of the problem: the config that ships is the config that was convenient during bring-up.</p>
|
| 92 |
+
<p>The reason a chatbot does not catch it is simple. It cannot see your sdkconfig. Paste a generated config into one and you get advice about symbols that may not exist in your IDF version. The free Kconfig hardening checkers that do exist target the Linux kernel, so the symbols that decide whether MCUboot accepts an unsigned image - CONFIG_BOOT_SIGNATURE_TYPE_NONE, CONFIG_BOOT_VALIDATE_SLOT0 - are not in their rule sets at all.</p>
|
| 93 |
+
<p>The timing is what changed. From 11 September 2026 the EU Cyber Resilience Act requires a manufacturer to report an actively exploited vulnerability in a product with digital elements: an early warning to ENISA and the national CSIRT within 24 hours, a full notification within 72 hours. A device that boots unsigned images is not a bug you patch quietly. It is a clock.</p>
|
| 94 |
+
<p>Firmware Release Gate is 18 rules that read ESP-IDF sdkconfig, sdkconfig.defaults and Zephyr prj.conf and name the line and the setting that replaces it. Open a file, run it, read the panel - the whole file, free, offline, no key asked. A licence adds the jobs that begin when one file is not enough: every config in the repository at once, the report file you keep with the release, and a JSON output that fails the build in CI.</p>
|
| 95 |
+
<p>Run it on a config you believe is clean. On a locked production build - secure boot on, flash encryption in Release mode, NVS encrypted, https OTA - it returns nothing at all. That is the point of a gate: it has to be able to say yes.</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/sku33021_result_card.jpg" style="width:100%;max-width:360px;border-radius:10px;display:block;margin:0 auto"><source src="/media/sku33021_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 Firmware Release Gate actually check?</summary><p style="margin:8px 0 2px;font:400 14.5px/1.6 system-ui,sans-serif;color:#33404b">It reads an ESP-IDF sdkconfig, a sdkconfig.defaults or a Zephyr prj.conf and reports the lines that a shipped unit should not carry: secure boot off, flash encryption in Development mode, a secure-boot escape hatch, unsigned MCUboot images, skipped TLS verification, plaintext http:// endpoints and hard-coded credentials. Each finding names the line number and the setting a release build should carry instead.</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 for?</summary><p style="margin:8px 0 2px;font:400 14.5px/1.6 system-ui,sans-serif;color:#33404b">Embedded firmware engineers who own the release build of an ESP32 or Zephyr product, and the one person on a small hardware team who signs off that a batch may be flashed. If you build with idf.py or west and the config lives in git, this reads the same files your build reads.</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 will a chatbot or a free checker not do this?</summary><p style="margin:8px 0 2px;font:400 14.5px/1.6 system-ui,sans-serif;color:#33404b">A chatbot cannot see your sdkconfig, and pasting a generated config into one gives you advice about symbols that may not exist in your IDF version. The free Kconfig hardening checkers in this space target the Linux kernel, not ESP-IDF or Zephyr and MCUboot, so the symbols that decide whether your device boots unsigned images are not in their rule sets.</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 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 audits the config file you have open, the whole file, with every finding and its remedy, and it never asks for a key. A licence adds the jobs that start when one file is not enough: auditing every config in the repository, exporting the report file you keep with the release, and a JSON output that fails the build in CI.</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 would this cost otherwise?</summary><p style="margin:8px 0 2px;font:400 14.5px/1.6 system-ui,sans-serif;color:#33404b">An outside firmware-only security review starts around $6,000, and a full IoT device assessment runs roughly $10,000 to $50,000. Those are worth paying for, but not to be told that flash encryption was left in Development mode. This is $29 once, so the review you pay for starts past the config layer.</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 does this matter now rather than at the next release?</summary><p style="margin:8px 0 2px;font:400 14.5px/1.6 system-ui,sans-serif;color:#33404b">From 11 September 2026 the EU Cyber Resilience Act requires a manufacturer to report an actively exploited vulnerability in a product with digital elements: an early warning to ENISA and the national CSIRT within 24 hours and a full notification within 72 hours. A unit that boots unsigned images or ships a hard-coded credential is not a bug you patch quietly, and units in the field cannot be re-configured.</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 not just ask ChatGPT or another AI chat?</summary><p style="margin:8px 0 2px;font:400 14.5px/1.6 system-ui,sans-serif;color:#33404b">A general AI chat answers from training data with a cutoff date, cannot read your repository and names no rule version. Firmware Release Gate checks the file you open against 18 rules from a rule set dated 2026-09-20, and points at the exact line. For a filing, an audit or a client you need that dated result on your own files.</p></details><script type="application/ld+json" data-yj="yj-faq-ld">{"@context": "https://schema.org", "@type": "FAQPage", "mainEntity": [{"@type": "Question", "name": "What does Firmware Release Gate actually check?", "acceptedAnswer": {"@type": "Answer", "text": "It reads an ESP-IDF sdkconfig, a sdkconfig.defaults or a Zephyr prj.conf and reports the lines that a shipped unit should not carry: secure boot off, flash encryption in Development mode, a secure-boot escape hatch, unsigned MCUboot images, skipped TLS verification, plaintext http:// endpoints and hard-coded credentials. Each finding names the line number and the setting a release build should carry instead."}}, {"@type": "Question", "name": "Who is this for?", "acceptedAnswer": {"@type": "Answer", "text": "Embedded firmware engineers who own the release build of an ESP32 or Zephyr product, and the one person on a small hardware team who signs off that a batch may be flashed. If you build with idf.py or west and the config lives in git, this reads the same files your build reads."}}, {"@type": "Question", "name": "Why will a chatbot or a free checker not do this?", "acceptedAnswer": {"@type": "Answer", "text": "A chatbot cannot see your sdkconfig, and pasting a generated config into one gives you advice about symbols that may not exist in your IDF version. The free Kconfig hardening checkers in this space target the Linux kernel, not ESP-IDF or Zephyr and MCUboot, so the symbols that decide whether your device boots unsigned images are not in their rule sets."}}, {"@type": "Question", "name": "What is free and what needs a licence?", "acceptedAnswer": {"@type": "Answer", "text": "Free audits the config file you have open, the whole file, with every finding and its remedy, and it never asks for a key. A licence adds the jobs that start when one file is not enough: auditing every config in the repository, exporting the report file you keep with the release, and a JSON output that fails the build in CI."}}, {"@type": "Question", "name": "What would this cost otherwise?", "acceptedAnswer": {"@type": "Answer", "text": "An outside firmware-only security review starts around $6,000, and a full IoT device assessment runs roughly $10,000 to $50,000. Those are worth paying for, but not to be told that flash encryption was left in Development mode. This is $29 once, so the review you pay for starts past the config layer."}}, {"@type": "Question", "name": "Why does this matter now rather than at the next release?", "acceptedAnswer": {"@type": "Answer", "text": "From 11 September 2026 the EU Cyber Resilience Act requires a manufacturer to report an actively exploited vulnerability in a product with digital elements: an early warning to ENISA and the national CSIRT within 24 hours and a full notification within 72 hours. A unit that boots unsigned images or ships a hard-coded credential is not a bug you patch quietly, and units in the field cannot be re-configured."}}, {"@type": "Question", "name": "Why not just ask ChatGPT or another AI chat?", "acceptedAnswer": {"@type": "Answer", "text": "A general AI chat answers from training data with a cutoff date, cannot read your repository and names no rule version. Firmware Release Gate checks the file you open against 18 rules from a rule set dated 2026-09-20, and points at the exact line. For a filing, an audit or a client you need that dated result on your own files."}}]}</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:33021,slug:"firmware-release-gate",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/en18031-psti-lint"><span class="yj-rel-t">EN 18031 / PSTI Device Config Lint</span><span class="yj-rel-p">$29</span></a><a class="yj-rel-c" href="https://getreadystack.com/tools/renpy-release-gate"><span class="yj-rel-t">Ren'Py Release Gate</span><span class="yj-rel-p">$29</span></a><a class="yj-rel-c" href="https://getreadystack.com/tools/pyproject-release-gate"><span class="yj-rel-t">pyproject.toml Release Gate (PEP 639)</span><span class="yj-rel-p">$29</span></a><a class="yj-rel-c" href="https://getreadystack.com/tools/lead-magnet-ebook-template"><span class="yj-rel-t">Lead Magnet Ebook Template - 20 Fill-In Templates to Build and Ship Your Email</span><span class="yj-rel-p">$49</span></a><a class="yj-rel-c" href="https://getreadystack.com/tools/webflow-restaurant-template"><span class="yj-rel-t">Webflow Restaurant Template — delivered as self-contained HTML you own: 26 pag</span><span class="yj-rel-p">$49</span></a><a class="yj-rel-c" href="https://getreadystack.com/tools/dotnet-eol-support-gate"><span class="yj-rel-t">.NET EOL & CRA Support Window Gate</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>
|