-
Notifications
You must be signed in to change notification settings - Fork 633
Open
Description
Task: Security, Privacy & Crisis Resources
Description
Implement security hardening (rate limiting, Helmet.js headers), content filtering for harmful AI advice, "Report this advice" button, crisis resource footer on every page, and legal pages (Terms of Service, Privacy Policy). Ensure WCAG 2.1 AA accessibility compliance.
Acceptance Criteria
- Content filtering layer detects harmful AI advice (abuse, self-harm, dangerous behaviors)
- "Report this advice" button on every guidance card
- Crisis resource footer on every page:
- National Suicide Prevention Lifeline: 988 (US)
- National Domestic Violence Hotline: 1-800-799-7233
- Crisis Text Line: Text HOME to 741741
- Rate limiting middleware (100 requests/15 minutes per IP)
- Helmet.js security headers configured
- Terms of Service page
- Privacy Policy page (GDPR/CCPA compliant)
- Disclaimer: "Not a substitute for professional therapy"
- WCAG 2.1 AA compliance (color contrast, keyboard navigation, screen reader support)
Technical Details
Content Filtering (src/services/content-filter.ts):
export class ContentFilter {
private dangerousKeywords = [
'kill yourself', 'suicide', 'self-harm', 'hurt yourself',
'abuse', 'hit', 'punch', 'violence', 'leave them',
'they deserve it', 'gaslight', 'manipulate'
];
async checkForHarmfulContent(aiResponse: string): Promise<{ isSafe: boolean; reason?: string }> {
const lowerResponse = aiResponse.toLowerCase();
for (const keyword of this.dangerousKeywords) {
if (lowerResponse.includes(keyword)) {
return {
isSafe: false,
reason: `Detected potentially harmful content: "${keyword}"`
};
}
}
// Additional check: Use Anthropic's content moderation API (if available)
// Or OpenAI's moderation endpoint
return { isSafe: true };
}
getFallbackMessage(mode: 'structured' | 'conversational'): string {
if (mode === 'conversational') {
return "I'm sorry, but I'm unable to provide guidance for this situation. If you're experiencing thoughts of self-harm or are in an unsafe relationship, please reach out to a crisis resource immediately. National Suicide Prevention Lifeline: 988. National Domestic Violence Hotline: 1-800-799-7233.";
}
return JSON.stringify({
summary: "Unable to provide guidance for this situation.",
crisis_resources: [
"National Suicide Prevention Lifeline: 988",
"National Domestic Violence Hotline: 1-800-799-7233",
"Crisis Text Line: Text HOME to 741741"
]
});
}
}
// Integrate in AI Orchestrator
async callClaude(prompt: string, mode: 'structured' | 'conversational') {
const response = await anthropic.messages.create({ ... });
const content = response.content[0].text;
const filterResult = await contentFilter.checkForHarmfulContent(content);
if (!filterResult.isSafe) {
console.error('Harmful content detected:', filterResult.reason);
await db.create('moderation_logs', {
conflict_id: currentConflictId,
reason: filterResult.reason,
flagged_at: new Date()
});
return contentFilter.getFallbackMessage(mode);
}
return mode === 'structured' ? JSON.parse(content) : content;
}Report Advice Button (ReportAdviceButton.tsx):
export function ReportAdviceButton({ guidanceId }: { guidanceId: string }) {
const [reported, setReported] = useState(false);
const handleReport = async () => {
await fetch(`/api/guidance/${guidanceId}/report`, { method: 'POST' });
setReported(true);
};
return (
<button
onClick={handleReport}
disabled={reported}
className="text-sm text-red-600 hover:underline"
>
{reported ? '✓ Reported' : '⚠ Report this advice'}
</button>
);
}Crisis Resource Footer (Footer.tsx):
export function Footer() {
return (
<footer className="bg-gray-100 border-t border-gray-300 py-6 mt-12">
<div className="max-w-4xl mx-auto px-4">
<div className="bg-red-50 border border-red-200 rounded p-4 mb-4">
<h3 className="font-semibold text-red-900 mb-2">🆘 In Crisis?</h3>
<p className="text-sm text-red-800">
If you're experiencing thoughts of self-harm or are in an abusive relationship:
</p>
<ul className="text-sm text-red-800 mt-2 space-y-1">
<li><strong>National Suicide Prevention Lifeline:</strong> 988 (US)</li>
<li><strong>National Domestic Violence Hotline:</strong> 1-800-799-7233</li>
<li><strong>Crisis Text Line:</strong> Text HOME to 741741</li>
</ul>
</div>
<p className="text-sm text-gray-600 text-center">
This app is not a substitute for professional mental health care. If you're in crisis, please contact emergency services or a licensed therapist immediately.
</p>
<div className="flex justify-center gap-4 mt-4 text-sm text-gray-600">
<a href="/terms" className="hover:underline">Terms of Service</a>
<span>|</span>
<a href="/privacy" className="hover:underline">Privacy Policy</a>
<span>|</span>
<a href="/contact" className="hover:underline">Contact</a>
</div>
</div>
</footer>
);
}Rate Limiting (src/middleware/rate-limit.ts):
import rateLimit from 'express-rate-limit';
export const apiLimiter = rateLimit({
windowMs: 15 * 60 * 1000, // 15 minutes
max: 100, // Limit each IP to 100 requests per window
standardHeaders: true,
legacyHeaders: false,
handler: (req, res) => {
res.status(429).json({
error: 'Too many requests, please try again later.'
});
}
});
// Apply to all API routes
app.use('/api/', apiLimiter);
// Stricter limit for auth endpoints
export const authLimiter = rateLimit({
windowMs: 15 * 60 * 1000,
max: 5, // 5 login attempts per 15 minutes
});
app.use('/api/auth/login', authLimiter);Security Headers (src/middleware/security.ts):
import helmet from 'helmet';
app.use(helmet({
contentSecurityPolicy: {
directives: {
defaultSrc: ["'self'"],
scriptSrc: ["'self'", "'unsafe-inline'"], // Allow inline scripts (React)
styleSrc: ["'self'", "'unsafe-inline'"], // Allow inline styles (Tailwind)
imgSrc: ["'self'", 'data:', 'https:'],
connectSrc: ["'self'", 'https://api.anthropic.com']
}
},
hsts: {
maxAge: 31536000,
includeSubDomains: true,
preload: true
}
}));Legal Pages:
- Create
/termsroute with Terms of Service (use template from Termly.io or consult lawyer) - Create
/privacyroute with Privacy Policy (GDPR/CCPA compliant, consult lawyer) - Disclaimer on homepage: "Not a substitute for professional therapy"
WCAG 2.1 AA Compliance:
- Color contrast ratio ≥ 4.5:1 (use WebAIM contrast checker)
- All interactive elements keyboard accessible (tab navigation)
- Focus indicators visible (outline on focused elements)
- Alt text for all images
- ARIA labels for icon-only buttons
- Screen reader testing with VoiceOver/NVDA
Dependencies
- Task 1 complete (backend API routes)
- Frontend Footer component location
- Legal review for Terms/Privacy (external consultant)
Effort Estimate
- Size: M
- Hours: 24-32 hours (3-4 days)
- Parallel: true (mostly independent of other tasks)
Definition of Done
- Content filtering detects harmful keywords, blocks response
- "Report this advice" button works, creates moderation log
- Crisis resource footer appears on every page
- Rate limiting prevents abuse (tested with 100+ requests)
- Helmet.js headers configured (verified with securityheaders.com)
- Terms of Service page published
- Privacy Policy page published (GDPR/CCPA compliant)
- WCAG 2.1 AA compliance verified (WebAIM WAVE tool, lighthouse audit)
- Unit tests for content filter
- E2E test: Report advice button creates log entry
- Manual testing: Keyboard navigation works for all forms
coderabbitai
Metadata
Metadata
Assignees
Labels
No labels