fix: Add security validation and sanitization for session titles

- Validate session ID format to prevent injection attacks
- Sanitize title input: limit to 256 chars, filter control characters
- Prevent potential security issues with malformed session titles
This commit is contained in:
Peter Steinberger 2025-07-01 12:48:34 +01:00
parent 98795cbb71
commit 646b478075
2 changed files with 37 additions and 2 deletions

View file

@ -143,6 +143,15 @@ export async function startVibeTunnelForward(args: string[]) {
const controlPath = path.join(os.homedir(), '.vibetunnel', 'control');
const sessionManager = new SessionManager(controlPath);
// Validate session ID format for security
if (!/^[a-zA-Z0-9_-]+$/.test(sessionId)) {
logger.error(
'Invalid session ID format. Only alphanumeric characters, hyphens, and underscores are allowed.'
);
closeLogger();
process.exit(1);
}
try {
// Load existing session info
const sessionInfo = sessionManager.loadSessionInfo(sessionId);
@ -152,11 +161,22 @@ export async function startVibeTunnelForward(args: string[]) {
process.exit(1);
}
// Sanitize the title - limit length and filter out problematic characters
const sanitizedTitle = updateTitle
.substring(0, 256) // Limit length
.split('')
.filter((char) => {
const code = char.charCodeAt(0);
// Allow printable characters (space to ~) and extended ASCII/Unicode
return code >= 32 && code !== 127 && (code < 128 || code > 159);
})
.join('');
// Update the title
sessionInfo.name = updateTitle;
sessionInfo.name = sanitizedTitle;
sessionManager.saveSessionInfo(sessionId, sessionInfo);
logger.log(`Session title updated to: ${updateTitle}`);
logger.log(`Session title updated to: ${sanitizedTitle}`);
closeLogger();
process.exit(0);
} catch (error) {

View file

@ -19,6 +19,7 @@ const logger = createLogger('session-manager');
export class SessionManager {
private controlPath: string;
private static readonly SESSION_ID_REGEX = /^[a-zA-Z0-9_-]+$/;
constructor(controlPath?: string) {
this.controlPath = controlPath || path.join(os.homedir(), '.vibetunnel', 'control');
@ -26,6 +27,18 @@ export class SessionManager {
this.ensureControlDirectory();
}
/**
* Validate session ID format for security
*/
private validateSessionId(sessionId: string): void {
if (!SessionManager.SESSION_ID_REGEX.test(sessionId)) {
throw new PtyError(
'Invalid session ID format. Only alphanumeric characters, hyphens, and underscores are allowed.',
'INVALID_SESSION_ID'
);
}
}
/**
* Ensure the control directory exists
*/
@ -45,6 +58,7 @@ export class SessionManager {
stdinPath: string;
sessionJsonPath: string;
} {
this.validateSessionId(sessionId);
const controlDir = path.join(this.controlPath, sessionId);
// Create session directory
@ -96,6 +110,7 @@ export class SessionManager {
* Save session info to JSON file
*/
saveSessionInfo(sessionId: string, sessionInfo: SessionInfo): void {
this.validateSessionId(sessionId);
try {
const sessionInfoStr = JSON.stringify(sessionInfo, null, 2);