security: enforce 0o600 permissions on WhatsApp credential files (#10529)
Merged via /review-pr -> /prepare-pr -> /merge-pr. Prepared head SHA: 4f10b7dc635e4220b6357a36bd0a7a116442b507 Co-authored-by: abdelsfane <32418586+abdelsfane@users.noreply.github.com> Co-authored-by: steipete <58493+steipete@users.noreply.github.com> Reviewed-by: @steipete
This commit is contained in:
@@ -7,6 +7,7 @@ Docs: https://docs.openclaw.ai
|
||||
### Fixes
|
||||
|
||||
- Security/Canvas: serve A2UI assets via the shared safe-open path (`openFileWithinRoot`) to close traversal/TOCTOU gaps, with traversal and symlink regression coverage. (#10525) Thanks @abdelsfane.
|
||||
- Security/WhatsApp: enforce `0o600` on `creds.json` and `creds.json.bak` on save/backup/restore paths to reduce credential file exposure. (#10529) Thanks @abdelsfane.
|
||||
- Security/Gateway + ACP: block high-risk tools (`sessions_spawn`, `sessions_send`, `gateway`, `whatsapp_login`) from HTTP `/tools/invoke` by default with `gateway.tools.{allow,deny}` overrides, and harden ACP permission selection to fail closed when tool identity/options are ambiguous while supporting `allow_always`/`reject_always`. (#15390) Thanks @aether-ai-agent.
|
||||
- MS Teams: preserve parsed mention entities/text when appending OneDrive fallback file links, and accept broader real-world Teams mention ID formats (`29:...`, `8:orgid:...`) while still rejecting placeholder patterns. (#15436) Thanks @hyojin.
|
||||
- Security/Audit: distinguish external webhooks (`hooks.enabled`) from internal hooks (`hooks.internal.enabled`) in attack-surface summaries to avoid false exposure signals when only internal hooks are enabled. (#13474) Thanks @mcaxtr.
|
||||
|
||||
@@ -68,6 +68,11 @@ export function maybeRestoreCredsFromBackup(authDir: string): void {
|
||||
// Ensure backup is parseable before restoring.
|
||||
JSON.parse(backupRaw);
|
||||
fsSync.copyFileSync(backupPath, credsPath);
|
||||
try {
|
||||
fsSync.chmodSync(credsPath, 0o600);
|
||||
} catch {
|
||||
// best-effort on platforms that support it
|
||||
}
|
||||
logger.warn({ credsPath }, "restored corrupted WhatsApp creds.json from backup");
|
||||
} catch {
|
||||
// ignore
|
||||
|
||||
@@ -73,6 +73,11 @@ async function safeSaveCreds(
|
||||
try {
|
||||
JSON.parse(raw);
|
||||
fsSync.copyFileSync(credsPath, backupPath);
|
||||
try {
|
||||
fsSync.chmodSync(backupPath, 0o600);
|
||||
} catch {
|
||||
// best-effort on platforms that support it
|
||||
}
|
||||
} catch {
|
||||
// keep existing backup
|
||||
}
|
||||
@@ -82,6 +87,11 @@ async function safeSaveCreds(
|
||||
}
|
||||
try {
|
||||
await Promise.resolve(saveCreds());
|
||||
try {
|
||||
fsSync.chmodSync(resolveWebCredsPath(authDir), 0o600);
|
||||
} catch {
|
||||
// best-effort on platforms that support it
|
||||
}
|
||||
} catch (err) {
|
||||
logger.warn({ error: String(err) }, "failed saving WhatsApp creds");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user