T09 · Insecure Skill Coding Practices
Warning
- Location
- scripts/linkedin.mjs:101
- Finding
- Legacy keychain credential is unnecessarily loaded into process memory<![CDATA[ ## Vulnerability Details **File Location**: `scripts/linkedin.mjs:101-115`, invoked by `scripts/linkedin.mjs:188-191` and `scripts/linkedin.mjs:704-723` **Vulnerability Type**: Credential overexposure during a presence check **Risk Level**: Medium ### Vulnerable Code ```js function keychainGet() { try { const argv = KEYCHAIN_BIN === 'security' ? ['find-generic-password', '-s', KEYRING_SERVICE, '-a', KEYRING_ACCOUNT, '-w'] : ['lookup', 'service', KEYRING_SERVICE, 'account', KEYRING_ACCOUNT]; const v = execFileSync(KEYCHAIN_BIN, argv, { encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'], }); const trimmed = String(v || '').replace(/\n$/, ''); return trimmed || null; } catch { return null; } } ``` The full value is retrieved merely to determine whether an entry exists: ```js function legacyCredsPresent() { return Boolean(keychainGet()) || existsSync(TOKEN_FILE); } ``` ### Technical Analysis The `session status` operation only needs a Boolean indication of whether a legacy keychain entry exists. Instead, `keychainGet()` invokes a platform credential command that returns the complete credential and captures that value in Node.js memory. The legacy entry is documented as potentially containing a password-equivalent LinkedIn session. Although the value is not printed or transmitted, retrieving it expands its exposure from the operating-system keychain into the Node.js heap and child-process output pipe. This is unnecessary for the declared presence-check functionality and contradicts the documentation's assertion that no cookie value is read into the process. The implementation therefore exceeds least-privilege requirements for `session status`. ### Attack Path 1. A LinkedIn session credential left by version 1.2.0 or earlier remains in the operating-system keychain. 2. The user or Agent runs `linkedin session status`. 3. `legacyCredsPresent()` calls `keychainGet()`. 4. `security . ...[truncated 841 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Replace value retrieval with a metadata-only existence query where the platform supports one. 2. On macOS, use a keychain query that checks the command's exit status without requesting `-w`, so the password is never returned. 3. If `secret-tool` cannot perform a metadata-only presence query, do not probe the legacy entry during `session status`. Report the state as unknown or instruct the user to run the explicit cleanup operation. 4. Keep secret retrieval entirely out of Node.js. For logout, invoke only the fixed deletion command and use its exit status to report whether deletion succeeded. 5. Update tests to install a mock keychain executable that fails if the status operation requests or captures the secret value. 6. Correct the documentation so that its credential-handling claims precisely match platform behavior. ]]>
