{"record":{"id":"93f5eea1567ba38c","repo":"zeroclaw-labs/zeroclaw","slug":"security-estop-require-otp-to-resume-true-but-secu","errorCode":null,"errorMessage":"security.estop.require_otp_to_resume=true but security.otp.enabled=false","messagePattern":"security\\.estop\\.require_otp_to_resume=true but security\\.otp\\.enabled=false","errorType":"validation","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"src/main.rs","lineNumber":6527,"sourceCode":"        .context(\"Config path must have a parent directory\")?;\n    let mut manager = security::EstopManager::load(&config.security.estop, config_dir)?;\n\n    match estop_command {\n        Some(EstopSubcommands::Status) => {\n            print_estop_status(&manager.status());\n            Ok(())\n        }\n        Some(EstopSubcommands::Resume {\n            network,\n            domains,\n            tools,\n            otp,\n        }) => {\n            let selector = build_resume_selector(network, domains, tools)?;\n            let mut otp_code = otp;\n            let otp_validator = if config.security.estop.require_otp_to_resume {\n                if !config.security.otp.enabled {\n                    bail!(\n                        \"security.estop.require_otp_to_resume=true but security.otp.enabled=false\"\n                    );\n                }\n                if otp_code.is_none() {\n                    let entered = secret_prompt(\"Enter OTP code\", false)?;\n                    if !entered.is_empty() {\n                        eprintln!(\"{}\", ta(\"cli-otp-received\", &[], \"  ✓ OTP received\"));\n                    }\n                    otp_code = Some(entered);\n                }\n\n                let store = security::SecretStore::new(config_dir, config.secrets.encrypt);\n                let (validator, enrollment_uri) =\n                    security::OtpValidator::from_config(&config.security.otp, config_dir, &store)?;\n                if let Some(uri) = enrollment_uri {\n                    println!(\n                        \"{}\",\n                        t(","sourceCodeStart":6509,"sourceCodeEnd":6545,"githubUrl":"https://github.com/zeroclaw-labs/zeroclaw/blob/88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc/src/main.rs#L6509-L6545","documentation":"`zeroclaw estop resume` refuses to run when `[security.estop] require_otp_to_resume = true` but `[security.otp] enabled = false`. Without OTP there is no validator to enforce the promised second factor, so ZeroClaw fails fast on the contradictory config instead of resuming unprotected.","triggerScenarios":"Running `zeroclaw estop resume` (with any selector) while estop.require_otp_to_resume is true and otp.enabled is false — the check fires before the OTP prompt or the secret store are touched.","commonSituations":"Applying a security-hardening checklist partially (estop flags set, OTP block skipped); templates that ship require_otp_to_resume=true; a config merge that dropped the [security.otp] section.","solutions":["Enable the OTP subsystem: set `enabled = true` under `[security.otp]`, then re-run `zeroclaw estop resume` (the first run prints an enrollment URI)","Or drop the OTP requirement: set `require_otp_to_resume = false` under `[security.estop]`","Keep both flags in one committed config template so they cannot drift apart again"],"exampleFix":"# before\n[security.estop]\nenabled = true\nrequire_otp_to_resume = true\n# [security.otp] missing or enabled = false\n# after\n[security.estop]\nenabled = true\nrequire_otp_to_resume = true\n[security.otp]\nenabled = true","handlingStrategy":"validation","validationCode":"r=\"$(zeroclaw config get security.estop.require_otp_to_resume 2>/dev/null)\"\no=\"$(zeroclaw config get security.otp.enabled 2>/dev/null)\"\n[ \"$r\" = \"true\" ] && [ \"$o\" != \"true\" ] && {\n  echo \"require_otp_to_resume=true but otp.enabled is off\"; exit 1;\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Treat estop and otp flags as one unit in config templates and linters","Add a config-consistency check to deployment scripts","Test `zeroclaw estop resume` in staging before relying on it in production"],"tags":["security","estop","otp","config","zeroclaw"],"backgroundTag":"conflicting-config-options","analyzedSha":"88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc","analyzedAt":"2026-08-23T01:07:41.857Z","schemaVersion":2},"datasetVersion":"2026-08-23T08:06:27.607Z"}