import { render } from 'react';
const post = {
date: '01/01/2025',
content: `<p>
<h1>My Post</h1>
<b>To be</b> or <em>not to be</em>
<script>console.log("👺 buhuhaha")</scri`+`pt>
</p>`
}
function Post({ post }) {
return (
<div>
<div>{post.date}</div>
<div>{post.content}</div>
</div>
)
}
render(<Post post={post} />);
import { render } from 'react';
const post = {
date: '01/01/2025',
content: `<p>
<h1>My Post</h1>
<b>To be</b> or <em>not to be</em>
<img src=x onerror="console.log('👺 XSS')">
</p>`
}
function Post({ post }) {
return (
<div>
<div>{post.date}</div>
<div
dangerouslySetInnerHTML={{
__html: post.content
}} />
</div>
)
}
render(<Post post={post} />);
import { render } from 'react';
const post = {
date: '01/01/2025',
content: `<p>
<h1>My Post</h1>
<b>To be</b> or <em>not to be</em>
<img src=x onerror="console.log('👺 XSS')">
</p>`
}
function sanitize(source: string) {
return source
.replace(/on\w+=".*"/g, "")
}
function Post({ post }) {
return (
<div>
<div>{post.date}</div>
<div
dangerouslySetInnerHTML={{
__html: sanitize(post.content)
}} />
</div>
)
}
render(<Post post={post} />);
// components/AdminPanel.tsx
import { useSession } from 'next-auth/react';
import { getCsrfToken } from 'next-auth/react';
export default function AdminPanel({ postId }: { postId: number }) {
const { data: session } = useSession();
const deletePost = async () => {
const csrfToken = await getCsrfToken();
await fetch('/api/posts/delete', {
method: 'DELETE',
body: JSON.stringify({
csrfToken,
postId
}),
});
};
if (session?.user.isAdmin) {
return <button onClick={deletePost}>Delete Post</button>;
}
return null;
}
// app/api/something/route.ts
import { cookies } from 'next/headers'
import { NextResponse, NextRequest } from 'next/server'
export async function POST(req: NextRequest) {
const body = await req.json()
const submittedToken = body.csrfToken
const cookieStore = await cookies()
const csrfCookie = cookieStore.get('next-auth.csrf-token')?.value
const realToken = csrfCookie?.split('|')[0] // token|hash
if (
!submittedToken || !realToken ||
submittedToken !== realToken) {
return NextResponse.json(
{ error: 'Invalid CSRF token' },
{ status: 403 }
)
}
return NextResponse.json({ message: 'CSRF valid!' })
}
// pages/api/posts/index.ts
import type { NextApiRequest, NextApiResponse } from 'next';
export default function handler(req: NextApiRequest, res: NextApiResponse) {
// Set CORS headers
res.setHeader(
'Access-Control-Allow-Origin',
'https://trusted-domain.com'
);
res.setHeader('Access-Control-Allow-Methods', 'GET');
res.setHeader('Access-Control-Allow-Headers', 'Content-Type');
if (req.method === 'GET') {
// Return posts
return res.status(200).json({ posts: [{ id: 1, title: 'Sample Post' }] });
}
return res.status(405).json({ error: 'Method not allowed' });
}