Shared hosting recon
Skill OmarEltak/legacy-prod-survival-kit/skills/shared-hosting-recon
Claude Code skills for the solo engineer who just inherited a 17-year-old production system. Audit, deploy, monitor, and report — without a DevOps team.
npx -y skills add OmarEltak/legacy-prod-survival-kit --skill shared-hosting-reconAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 0 stars0 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
What its author says it does
Copied from the file, not written here
Use at the START of any engagement on a shared cPanel / Plesk / DirectAdmin host. Discovers disabled PHP functions, available APIs, /tmp permissions, security holes, file-system surprises, and host-side quirks BEFORE making architecture decisions. Especially valuable when you have no shell access. Surfaces everything that will surprise you 4 hours from now.
SKILL.md
14.1 KB, ~3.6k tokens by cl100k_base, as published. Nobody here has run it
Shared-hosting reconnaissance
When to use this
You're about to do engineering work on a production system hosted on shared hosting (cPanel, Plesk, DirectAdmin, etc.) where you don't have SSH/shell access. Before you write a deploy script, before you choose an architecture, before you trust anything: you do reconnaissance.
This skill is a checklist. Walk through it once, completely, at the start. The findings will inform every architectural decision you make for the next 8 hours.
Specifically use this when:
- You inherited a hosting account and need to know what's possible.
- A standard tool isn't working and you don't know why.
- You're considering using a PHP function or library and need to confirm it exists.
- You're about to commit to a deploy mechanism (cPanel Git VC, FTP, GitHub Actions over SSH) and need to know if it'll work.
Do NOT use this for:
- Cloud-native environments (AWS, GCP, Azure, Fly.io, Railway, Vercel) — they don't have these constraints.
- Dedicated servers / VPS where you have root — use standard sysadmin tooling.
- "I just want to deploy a small static site" — overkill.
The recon checklist
Walk through every section. Don't skip any. The ones you skip are the ones that will surprise you later.
A. PHP capabilities (most important — affects everything)
Upload a small _recon.php to the document root with this content. Run it once. Note every output. Delete it afterwards.
<?php
header('Content-Type: text/plain');
echo "=== PHP ===\n";
echo "version: " . PHP_VERSION . "\n";
echo "sapi: " . php_sapi_name() . "\n";
echo "uname: " . php_uname() . "\n";
echo "os: " . PHP_OS . "\n";
echo "\n=== INI ===\n";
$inis = ['memory_limit', 'max_execution_time', 'allow_url_fopen', 'allow_url_include',
'open_basedir', 'safe_mode', 'disable_functions', 'disable_classes',
'upload_max_filesize', 'post_max_size', 'max_input_time', 'session.save_path',
'date.timezone', 'short_open_tag', 'display_errors', 'log_errors',
'error_log'];
foreach ($inis as $k) echo "$k: " . ini_get($k) . "\n";
echo "\n=== Functions (commonly disabled on shared hosting) ===\n";
$fns = ['exec','passthru','shell_exec','system','popen','proc_open','proc_close',
'curl_exec','curl_multi_exec','escapeshellarg','escapeshellcmd',
'file_get_contents','fopen','fsockopen','pfsockopen','stream_socket_client',
'mail','dl','phpinfo','getmypid','posix_getpwuid','posix_kill',
'symlink','link','readlink','chmod','chown','chgrp'];
foreach ($fns as $f) {
echo str_pad("$f:", 32) . (function_exists($f) ? 'AVAILABLE' : 'DISABLED') . "\n";
}
echo "\n=== Classes (commonly relied on for deploy/zip work) ===\n";
$classes = ['ZipArchive','PharData','Phar','SplFileObject','RecursiveDirectoryIterator',
'RecursiveIteratorIterator','PDO','mysqli','SoapClient','DOMDocument'];
foreach ($classes as $c) {
echo str_pad("$c:", 32) . (class_exists($c) ? 'AVAILABLE' : 'MISSING') . "\n";
}
echo "\n=== Extensions ===\n";
echo implode(', ', get_loaded_extensions()) . "\n";
echo "\n=== Filesystem ===\n";
$paths = ['/tmp', sys_get_temp_dir(), getcwd(), dirname(__FILE__),
$_SERVER['DOCUMENT_ROOT'] ?? '?',
dirname($_SERVER['DOCUMENT_ROOT'] ?? '/')];
foreach (array_unique(array_filter($paths)) as $p) {
$perms = file_exists($p) ? sprintf('%04o', fileperms($p) & 0777) : 'MISSING';
$w = is_writable($p) ? 'W' : '-';
$r = is_readable($p) ? 'R' : '-';
$link = is_link($p) ? ' -> ' . @readlink($p) : '';
echo str_pad($p, 50) . " mode=$perms $r$w$link\n";
}
echo "\n=== Server ===\n";
foreach (['SERVER_SOFTWARE','GATEWAY_INTERFACE','DOCUMENT_ROOT','SERVER_ADDR',
'HTTP_HOST','HTTPS'] as $k) {
echo str_pad("$k:", 24) . ($_SERVER[$k] ?? '(unset)') . "\n";
}
Critical things to look for:
| Output | What it means | What to do |
|---|---|---|
passthru: DISABLED | No shell-out from PHP | Cannot use tar, rsync, git from PHP. Build deploy in pure PHP using ZipArchive or PharData. |
curl_exec: DISABLED | cURL functions disabled | Use file_get_contents() with stream_context_create() for HTTP requests. Confirm allow_url_fopen=1. |
allow_url_fopen: 0 | Cannot fetch URLs from PHP | Major problem for any deploy that pulls from GitHub. Check if fsockopen works as fallback. |
ZipArchive: AVAILABLE | Zip extraction works | Good — can use GitHub zipball API for deploys. |
ZipArchive: MISSING | No zip lib | Try PharData instead (uses tar.gz). |
open_basedir: <something> | Can only access listed paths | Note the constraint. Cannot read/write outside it. |
/tmp mode=0755 (instead of 1777) | Cannot write temp files as user | Critical: breaks cPanel's own deploy task runner. Build your deploy outside of any tooling that needs /tmp. |
/home/<user>/tmp -> /tmp | Symlink to broken /tmp | Same as above. |
disable_functions: includes escapeshellarg | Even arg-escaping disabled | Strong signal hosting locked down hard. Plan for pure-PHP everything. |
B. cPanel / control panel API capabilities
If on cPanel, test the UAPI (User API). Hit each in the browser while logged into cPanel:
/cpsess<session>/execute/Fileman/list_files?dir=/home/<user>
/cpsess<session>/execute/Fileman/get_file_content?dir=/home/<user>&file=test.txt
/cpsess<session>/execute/Fileman/save_file_content (POST)
/cpsess<session>/execute/VersionControl/list_repositories
Check which functions return {"status":1} and which return {"errors":["The system could not find the function..."]}. Different cPanel versions expose different UAPI surfaces.
Functions commonly missing on older cPanel:
Fileman/compressFileman/chmodFileman/remove_filesFileman/rename_fileFileman/move_files_to_trashFileman/empty_trash
If most of these are missing, you're stuck with: list, read, write. You'll need to do anything else (delete, chmod, rename) via the File Manager UI by clicking, OR by uploading PHP that does it.
C. cPanel session token / "security token" rules
cPanel URLs have a cpsess<digits> segment. This is per-session. If your session is invalidated:
- All cached cPanel URLs become invalid.
- The
FilemanAPI returns 401 with "Invalid Security Token." - Fix: log in fresh, get a new
cpsessvalue, replay the request.
If you're scripting via a browser tool, always extract the cpsess fresh from the current URL rather than caching it. We learned this the hard way.
D. cPanel Git Version Control (if present)
In cPanel → Git Version Control:
- Note: warning at top says "Your system administrator must enable shell access to allow you to view clone URLs." This is misleading — it's only about the SSH clone URL display, not deploys themselves.
- Try clicking "Create" → enter a clone URL with embedded credentials (
https://user:[email protected]/...). cPanel rejects this with "The clone URL cannot include a password." Workaround: write~/.git-credentialsand~/.gitconfigfirst via the Fileman API, then use plain HTTPS clone URL. - Try clicking "Deploy HEAD Commit." Watch the result. Then immediately read
~/.cpanel/logs/user_task_runner.log. The cPanel UI sometimes reports "complete" when the underlying task failed. The log file is the source of truth. - Common deploy failure:
Permission denied creating /home/<user>/tmp/...tmp.... This means/tmpis mode 0755 instead of 1777 (server-wide misconfig). cPanel's deploy is broken on this host. You need a custom PHP-based deploy.
E. Disk usage and quota
cPanel → Disk Usage (or directly: /cpsess<>/frontend/paper_lantern/diskusage/)
Note:
- Total disk used.
- Per-top-dir breakdown (often hidden — sort by size).
- Look for unidentified large files at the document root. We found 37 GB of mystery binary files (
zikqEi0T,ziCYIb3s, etc.) — old account-transfer artifacts, probably, but they were publicly downloadable.
F. Security audit (the bare minimum)
Walk the document root looking for these — they are surprisingly common on legacy hosting:
| File / pattern | Risk | Action |
|---|---|---|
phpinfo.php, info.php, pinfo.php | Information disclosure (PHP version, env, paths) | Delete immediately. |
mysqldumper.php, adminer.php, phpmyadmin.php (outside phpmyadmin/) | Public DB admin tool | Move outside web root or delete. |
*.sql, dump.sql, db.sql.gz at web root | DB contents downloadable | Move out of web root. |
*.zip, backup.tar.gz at web root | Backup downloadable | Move out of web root. |
_old.php, *.bak, *.orig | Old code accessible | Audit; delete or rename. |
.git, .svn directories at web root | Source code leak | Block via .htaccess or remove. |
| Random binary files with no extension and no obvious purpose | Unknown — investigate | Run file (if shell) or check magic bytes via Fileman/get_file_content. |
WordPress wp-config.php~, wp-config.php.bak | Credentials leak | Delete. |
G. PHP error log location
echo ini_get('error_log');
Note the path. Tail it to see what's actually happening on your prod. You will be amazed at how many silent errors are happening that nobody knows about.
If error_log is empty (i.e., logs go to Apache's), check ~/access-logs/ or ~/logs/ or the cPanel Errors page.
H. Existing cron jobs
cPanel → Cron Jobs
List everything currently scheduled. You inherit these. Some may be:
- Backup scripts written by the previous developer.
- Cleanup scripts that run mysteriously.
- Calls to deprecated services.
Read each cron command. If it's incomprehensible, find the script and read it. Don't disable any cron until you know what it does.
I. Database snapshot
cPanel → phpMyAdmin → Export → SQL → Save
Take a one-time DB dump as part of recon. Even if you do nothing else with it, you have a recovery point that's not the host's responsibility.
J. DNS and SSL
cPanel → Zone Editor (or DNS Zone Editor)
cPanel → SSL/TLS Status
Confirm:
- The domain points where you think it does.
- SSL certs aren't expiring in the next 7 days.
- AAAA records make sense (or don't exist if you don't want IPv6).
K. Existing repos / version control state
If cPanel → Git Version Control shows existing repositories, list them with their paths. Don't delete them — they may be legitimate or may be the previous developer's experiments. Just note they exist.
Output format
Produce a structured Markdown document with these sections:
# Shared-hosting reconnaissance: <hostname>
Date: <YYYY-MM-DD>
## PHP capabilities
- Version: ...
- Disabled functions: ... (highlight: passthru, exec, etc.)
- Available classes: ZipArchive, PharData, ...
- Critical INI settings: ...
- Filesystem: /tmp mode=..., ...
## cPanel API surface
- Working: list_files, save_file_content, get_file_content
- Missing: compress, chmod, ...
## /tmp situation
- /home/<user>/tmp -> /tmp (mode 0755) ⚠️ BROKEN
- Implication: cPanel deploys will fail silently. Custom PHP deploy required.
## Disk usage breakdown
- Total: ... GB
- public_html: ... GB (which is ... % code, ... % media)
- Mystery files at web root: ...
## Security findings
- ⚠️ admin/phpinfo.php (info disclosure) — DELETE
- ⚠️ test/admin/mysqldumper.php (public DB tool) — MOVE OUT OF WEB ROOT
- ⚠️ Database dump downloadable at /db.sql — MOVE
- 4 unidentified binary files totalling 37 GB at web root — INVESTIGATE
## Pre-existing automation
- 3 cron jobs found: <list with descriptions>
- 1 git repository in ~/repositories/<name>: <last update, purpose>
## Architectural implications
- Cannot use cPanel's native deploy (broken /tmp).
- Cannot shell out from PHP (disabled functions).
- Have ZipArchive + PharData + allow_url_fopen → can fetch + extract zips.
- Recommended deploy mechanism: <X>.
## What to fix immediately (before any other work)
1. Delete <list of security holes>
2. Take a DB backup
3. Document existing cron jobs
## What to defer
- <list of nice-to-haves>
This document becomes your reference for the rest of the engagement. Every architectural decision should cite a specific line from it.
Common mistakes to avoid
- Skipping section A. "I'll just check disabled functions when I need them." No — knowing the full list upfront saves you from designing around a function that turns out not to exist.
- Trusting the cPanel UI. It often reports success when the underlying task failed. The log files are the source of truth.
- Assuming standard Linux conventions hold. On legacy shared hosts,
/tmpmay be wrong./home/<user>/tmpmay be a symlink./usr/bin/tarmay not be reachable from PHP. Test, don't assume. - Not taking a DB snapshot. It's free, takes 5 minutes, and is the one thing you'll regret skipping.
Why this skill exists
In one engagement, the order of discovery was:
- Try cPanel's native Git deploy. It "succeeds."
- Site doesn't update. Confused.
- Read
~/.cpanel/logs/user_task_runner.log. SeePermission denied: /home/reg/tmp/.... - Investigate
/home/reg/tmp. Discover it's a symlink to/tmp. - Discover
/tmpis mode 0755 instead of 1777. - Realize cPanel's deploy is fundamentally broken on this host.
- Plan custom PHP deploy.
- Try
passthru('tar ...'). Returns empty. - Try
system. Same. - Read
disable_functions. See:passthru, exec, shell_exec, system, popen, proc_open, curl_exec, escapeshellarg, .... - Realize need pure-PHP deploy with no shell.
- Check if
ZipArchiveis available. It is. Build around that.
Each of those discoveries took 5–30 minutes in the moment, with bewildered "why is this happening" energy. This skill compresses the entire chain into one upfront pass: 30 minutes of recon and you know everything you needed to know.
The skill is short. The pain it prevents is not.