Files
nanoclaw/src/types.ts
gavrielc 48822ff67d Add mount security allowlist for external directory access (#14)
* Add secure mount allowlist validation

Addresses arbitrary host mount vulnerability by validating additional
mounts against an external allowlist stored at ~/.config/nanoclaw/.
This location is never mounted into containers, making it tamper-proof.

Security measures:
- Allowlist cached in memory (edits require process restart)
- Real path resolution (blocks symlink and .. traversal attacks)
- Blocked patterns for sensitive paths (.ssh, .gnupg, .aws, etc.)
- Non-main groups forced to read-only when nonMainReadOnly is true
- Container path validation prevents /workspace/extra escape

https://claude.ai/code/session_01BPqdNy4EAHHJcdtZ27TXkh

* Add mount allowlist setup to /setup skill

Interactive walkthrough that asks users:
- Whether they want agents to access external directories
- Which directories to allow (with paths)
- Read-write vs read-only for each
- Whether non-main groups should be restricted to read-only

Creates ~/.config/nanoclaw/mount-allowlist.json based on answers.

https://claude.ai/code/session_01BPqdNy4EAHHJcdtZ27TXkh

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-02-01 22:55:08 +02:00

80 lines
2.1 KiB
TypeScript

export interface AdditionalMount {
hostPath: string; // Absolute path on host (supports ~ for home)
containerPath: string; // Path inside container (under /workspace/extra/)
readonly?: boolean; // Default: true for safety
}
/**
* Mount Allowlist - Security configuration for additional mounts
* This file should be stored at ~/.config/nanoclaw/mount-allowlist.json
* and is NOT mounted into any container, making it tamper-proof from agents.
*/
export interface MountAllowlist {
// Directories that can be mounted into containers
allowedRoots: AllowedRoot[];
// Glob patterns for paths that should never be mounted (e.g., ".ssh", ".gnupg")
blockedPatterns: string[];
// If true, non-main groups can only mount read-only regardless of config
nonMainReadOnly: boolean;
}
export interface AllowedRoot {
// Absolute path or ~ for home (e.g., "~/projects", "/var/repos")
path: string;
// Whether read-write mounts are allowed under this root
allowReadWrite: boolean;
// Optional description for documentation
description?: string;
}
export interface ContainerConfig {
additionalMounts?: AdditionalMount[];
timeout?: number; // Default: 300000 (5 minutes)
env?: Record<string, string>;
}
export interface RegisteredGroup {
name: string;
folder: string;
trigger: string;
added_at: string;
containerConfig?: ContainerConfig;
}
export interface Session {
[folder: string]: string;
}
export interface NewMessage {
id: string;
chat_jid: string;
sender: string;
sender_name: string;
content: string;
timestamp: string;
}
export interface ScheduledTask {
id: string;
group_folder: string;
chat_jid: string;
prompt: string;
schedule_type: 'cron' | 'interval' | 'once';
schedule_value: string;
context_mode: 'group' | 'isolated';
next_run: string | null;
last_run: string | null;
last_result: string | null;
status: 'active' | 'paused' | 'completed';
created_at: string;
}
export interface TaskRunLog {
task_id: string;
run_at: string;
duration_ms: number;
status: 'success' | 'error';
result: string | null;
error: string | null;
}