other
Error
- Location
- lib/form_filler.mjs:232
- Finding
- Indirect prompt injection through job application fields can disclose stored candidate answers<![CDATA[ ## Vulnerability Details **File Location**: `lib/form_filler.mjs:232-276, 573-575, 594-596, 619-620, 697-700`; `lib/apply/easy_apply.mjs:208-220, 278-297` **Vulnerability Type**: Indirect prompt injection with automatic external submission **Risk Level**: High ### Vulnerable Code ```js async aiAnswerFor(label, opts = {}) { if (!this.apiKey) return null; const savedAnswers = this.answers.map(a => `Q: "${a.pattern}" -> A: "${a.answer}"`).join('\n'); const optionsHint = opts.options?.length ? `\nAvailable options: ${opts.options.join(', ')}` : ''; const systemPrompt = `You are helping a job candidate fill out application forms. You have access to their profile and previously answered questions. Rules: - If this question is a variation of a previously answered question, return the SAME answer - For yes/no or multiple choice, return ONLY the exact option text - For short-answer fields, be brief and direct (1 line) - Use first person - Never make up facts - Just the answer text — no preamble, no explanation, no quotes`; const userPrompt = `Candidate: ${this.profile.name?.first} ${this.profile.name?.last} Location: ${this.profile.location?.city}, ${this.profile.location?.state} Years experience: ${this.profile.years_experience || 7} Applying for: ${this.jobContext.title || 'a role'} at ${this.jobContext.company || 'a company'} Previously answered questions: ${savedAnswers || '(none yet)'} New question: "${label}"${optionsHint} Answer:`; try { const res = await fetch(ANTHROPIC_API_URL, { method: 'POST', headers: { 'Content-Type': 'application/json', 'x-api-key': this.apiKey, 'anthropic-version': '2023-06-01', }, body: JSON.stringify({ model: 'claude-sonnet-4-6', max_tokens: 256, system: systemPrompt, messages: [{ role: 'user', content: userPrompt }], }), }); if (!res.ok) return null; const data = await res.json(); const answer = data. ...[truncated 3727 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Do not place the entire `answers.json` collection into every model prompt. Retrieve only one or a small number of answers that were locally matched as relevant to the current field. 2. Treat labels, placeholders, job titles, company names, and options as untrusted data. Clearly delimit them and tell the model that content inside the delimiters is data, not instructions. 3. Reject or escalate fields containing instruction-like language, requests to reveal context, encoded content, URLs, secrets, previous answers, system prompts, or unrelated data. 4. Require explicit user approval before submitting any AI-generated free-text response. Automatic submission should be limited to deterministic profile mappings and previously approved exact answers. 5. Use structured model output with a strict schema, maximum length, and field-type constraints. 6. For multiple-choice questions, only accept exact values from the page’s option allowlist. Do not use substring matching for security-sensitive questions. 7. Keep sensitive answer categories out of model context unless strictly required for the current field. 8. Mark model-generated answers separately and do not persist them as trusted reusable answers until the user confirms them. 9. Add adversarial tests covering labels that request previous answers, candidate profile data, model instructions, hidden context, or unrelated output. ]]>
