- Location
- src/lib/cookie-manager.ts:19
- Finding
- Authentication Cookies Are Stored in Plaintext Without Restrictive File Permissions<![CDATA[
## Vulnerability Details
**File Location**: `src/lib/cookie-manager.ts:19-32`; related directory configuration in `src/lib/config.ts:16-21, 45-48`
**Vulnerability Type**: Plaintext storage of sensitive session credentials with unsafe default permissions
**Risk Level**: High
### Vulnerable Code
```ts
// src/lib/cookie-manager.ts:19-32
async saveCookies(cookies: CookieData['cookies']): Promise<void> {
ensureCookieDir();
const config = getConfig();
const now = new Date();
const expiresAt = new Date(now.getTime() + config.cookieExpiryDays * 24 * 60 * 60 * 1000);
const cookieData: CookieData = {
cookies,
createdAt: now.toISOString(),
expiresAt: expiresAt.toISOString(),
};
const cookiePath = getCookiePath(this.platform);
fs.writeFileSync(cookiePath, JSON.stringify(cookieData, null, 2), 'utf-8');
}
```
```ts
// src/lib/config.ts:16-21
const defaultConfig: Config = {
cookieDir: path.join(process.cwd(), 'data', 'cookies'),
cookieExpiryDays: 30,
headless: false,
timeout: 60000,
slowMo: 100,
};
```
```ts
// src/lib/config.ts:45-48
export function ensureCookieDir(): string {
const config = getConfig();
if (!fs.existsSync(config.cookieDir)) {
fs.mkdirSync(config.cookieDir, { recursive: true });
}
```
### Technical Analysis
The application persists complete Playwright session cookies as unencrypted, human-readable JSON. These cookies may contain bearer credentials that allow an authenticated browser session to be reconstructed without knowing the user's password or repeating QR-code authentication.
Neither `mkdirSync` nor `writeFileSync` specifies a restrictive permission mode. Effective permissions therefore depend on the process umask. On common Unix-like configurations, the directory may be created as `0755` and the cookie files as `0644`, potentially allowing other local users to discover and read the stored credentials.
The cookie directory is also based on `process.cwd()`. If the application is launc
...[truncated 1759 chars]
- Remediation
- <![CDATA[
## Remediation Suggestions
1. Create the credential directory with owner-only permissions:
```ts
fs.mkdirSync(config.cookieDir, {
recursive: true,
mode: 0o700,
});
fs.chmodSync(config.cookieDir, 0o700);
```
2. Write cookie files with mode `0600` and avoid following attacker-controlled symbolic links. Use an exclusive or atomic write process where appropriate:
```ts
fs.writeFileSync(cookiePath, JSON.stringify(cookieData), {
encoding: 'utf-8',
mode: 0o600,
flag: 'w',
});
fs.chmodSync(cookiePath, 0o600);
```
3. Store credentials in a per-user application data directory rather than under `process.cwd()`. Ensure the location is outside repositories, shared directories, and cloud-synchronized folders.
4. Prefer an operating-system credential store such as Keychain, Credential Manager, or Secret Service. If file storage is unavoidable, encrypt cookie data using a key protected by the operating system rather than storing the encryption key beside the data.
5. Validate the resolved cookie path, reject symbolic links, and ensure the final path remains inside the intended credential directory before reading, writing, or deleting it.
6. Minimize retention time and store only cookies required for the authenticated workflow. Do not assume the locally recorded 30-day expiration matches the platform's real cookie expiration.
7. Add `data/cookies/` and test screenshots to `.gitignore`, backup exclusions, and packaging exclusions.
8. On logout, invalidate the server-side session where supported instead of only deleting the local file. Securely revoke all associated authentication tokens.
9. Document that cookie files are bearer credentials and must not be copied, committed, logged, shared, or attached to support requests.
]]>