Security hardening: fix all 8 blocking findings for PR #419

Fix 1: Update support.js to collect SSH public key and POST JSON
Fix 2: Legacy njalla.sh migration - parse safely, archive non-executable, replace cron with systemd timer
Fix 3: DDNS SSRF prevention - allowlist only njal.la, reject other hosts, disable curl redirects
Fix 4: Legacy root support-key removal migration (_remove_legacy_root_support_key)
Fix 5: Automatic support-key expiration (expires_at + _expire_support_if_stale)
Fix 6: Move security helpers to security_helpers.py, tests import production code
Fix 7: Real NIP-19/Bech32 npub validation (_bech32_decode + _validate_npub)
Fix 8: Replace journalctl sudo wildcard with restricted sovran-journal-helper.py
Also: Make _write_hub_overrides() atomic with tempfile+os.replace
94 tests passing

Co-authored-by: naturallaw777 <99053422+naturallaw777@users.noreply.github.com>
This commit is contained in:
copilot-swe-agent[bot]
2026-08-11 12:07:18 +00:00
committed by GitHub
co-authored by naturallaw777
parent 9b77b04741
commit a111de1ece
8 changed files with 1256 additions and 362 deletions
+44 -3
View File
@@ -110,12 +110,26 @@ function renderSupportInactive() {
'</div>',
'<div class="support-steps"><div class="support-steps-title">What happens:</div><ol>',
'<li>A restricted <code>sovran-support</code> user is created with limited access</li>',
'<li>Our SSH key is added only to that restricted account</li>',
'<li>Support\'s SSH key is added only to that restricted account — not to root</li>',
'<li>Wallet files are locked via access controls — not visible to support</li>',
'<li>You control if and when wallet access is granted (time-limited)</li>',
'<li>All session events are logged for your audit</li>',
'<li>Access expires automatically after 24 hours</li>',
'</ol></div>',
'<div class="support-key-section">',
'<label class="support-key-label" for="support-ssh-pubkey">',
'<strong>Paste the support SSH public key provided by Sovran Systems:</strong>',
'</label>',
'<textarea id="support-ssh-pubkey" class="support-key-input" rows="3" ',
'placeholder="ssh-ed25519 AAAA… support-session" ',
'spellcheck="false" autocomplete="off" autocorrect="off" autocapitalize="off"></textarea>',
'<p class="support-key-hint">',
'The key must start with <code>ssh-ed25519</code> or <code>ecdsa-sha2-nistp256</code>. ',
'Do not paste your own private key — only paste the one-time public key sent by Sovran Systems support.',
'</p>',
'</div>',
'<button class="btn support-btn-enable" id="btn-support-enable">Enable Support Access</button>',
'<p id="support-key-error" class="support-key-error" style="display:none;color:#c0392b;margin-top:8px;"></p>',
'<p class="support-fine-print">You can revoke access at any time. When you end the session, you\'ll be able to disable SSH to return to the default secure state.</p>',
'</div>',
].join("");
@@ -227,16 +241,43 @@ function renderSupportRemoved(verified) {
async function enableSupport() {
var btn = document.getElementById("btn-support-enable");
var errEl = document.getElementById("support-key-error");
var textarea = document.getElementById("support-ssh-pubkey");
if (errEl) { errEl.style.display = "none"; errEl.textContent = ""; }
var sshKey = textarea ? textarea.value.trim() : "";
if (!sshKey) {
if (errEl) { errEl.textContent = "Please paste the SSH public key provided by Sovran Systems support."; errEl.style.display = "block"; }
return;
}
// Client-side pre-validation: key must start with a known algorithm prefix
var validPrefixes = ["ssh-ed25519 ", "ecdsa-sha2-nistp256 ", "ecdsa-sha2-nistp384 ", "ecdsa-sha2-nistp521 ", "sk-ssh-ed25519@openssh.com "];
var hasValidPrefix = validPrefixes.some(function(p) { return sshKey.startsWith(p); });
if (!hasValidPrefix) {
if (errEl) { errEl.textContent = "Invalid key format. The key must start with ssh-ed25519 or ecdsa-sha2-nistp256. Do not paste a private key."; errEl.style.display = "block"; }
return;
}
if (sshKey.indexOf("\n") !== -1) {
if (errEl) { errEl.textContent = "The key must be a single line. Please check the pasted value."; errEl.style.display = "block"; }
return;
}
if (btn) { btn.disabled = true; btn.textContent = "Enabling…"; }
try {
await apiFetch("/api/support/enable", { method: "POST" });
await apiFetch("/api/support/enable", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ ssh_public_key: sshKey }),
});
var status = await apiFetch("/api/support/status");
_supportStatus = status;
_supportEnabledAt = status.enabled_at;
renderSupportActive(status);
} catch (err) {
if (btn) { btn.disabled = false; btn.textContent = "Enable Support Access"; }
alert("Failed to enable support access. Please try again.");
var detail = (err && err.detail) ? err.detail : "Failed to enable support access. Please check the key and try again.";
if (errEl) { errEl.textContent = detail; errEl.style.display = "block"; }
else { alert(detail); }
}
}