| name | alibabacloud-website-malware-check |
| description | Read-only detection of website defacement/hijacking via page source,
hidden SEO links, suspicious redirects, and cloaking, corroborated
best-effort by Security Center and WAF.
Use when a user suspects their website is hacked, reports an
unauthorized web compromise, or has malicious code injected; sees
abnormal redirects (even refresh-only), hidden black-hat SEO links,
mobile vs desktop content differences (cloaking), or a defaced
homepage. ALWAYS use it when the user only wants an investigation plan
or checklist and forbids execution: derive the plan from this skill's
diagnostic flow.
Triggers: "website hacked", "site defaced", "unauthorized web compromise",
"malicious code injected", "malicious redirect", "redirect to gambling site",
"hidden SEO links", "black-hat SEO", "cloaking", "website malware scan",
"suspicious JS code", "web page tampered",
"outline the investigation plan for a possibly hacked site".
|
Website Malware Check (Defacement / Hijacking Diagnostics)
Diagnose whether a website has been defaced or hijacked: "my site redirects visitors to a gambling page", "mobile users are redirected but desktop looks fine", "an abnormal redirect appears after I refresh the page", "search-engine users land on hidden spam links", "malicious JS was injected into my pages".
Core approach: first fetch and analyze the target page locally - page source, hidden SEO links, suspicious redirect code, hidden iframes, and suspicious external resources. If redirect suspicion or device/UA differences remain, run a multi-UA probe matrix to confirm server-side cloaking. Finally, corroborate local findings with best-effort read-only cloud lookups in Security Center (SAS) and WAF. Every step is read-only; the skill never modifies the target website.
Core Capabilities
This skill declares three capabilities:
- Static defacement scan - Analyze page source for hidden SEO links, suspicious redirects (meta refresh, JavaScript redirects, hidden iframes), and suspicious external scripts/links; locate malicious JS precisely with a source-mode deep dive over all external script files.
- Cloaking and multi-UA detection - Compare responses across desktop / mobile / in-app / search-engine User-Agent and Referer combinations to detect server-side cloaking, where the server serves different (malicious) content to specific visitors.
- Cloud read-only corroboration - Best-effort read-only lookups in Security Center (suspicious events) and WAF (domain access detail) to corroborate local findings. Failures, empty results, or not-enabled services never block the diagnosis; the report states the skip reason and continues.
Detailed detection rules, the suspicious-keyword library, and the known-malicious-domain rule base live in references/detection-capabilities.md. Injection classification is defined in references/injection-types.md.
Observability
All OpenAPI calls (invoked through the aliyun CLI) include:
- User-Agent:
--user-agent AlibabaCloud-Agent-Skills/{SKILL_NAME}/{session-id}
- SKILL_NAME:
alibabacloud-website-malware-check
- session-id: 32-character hex string generated per diagnostic session; the same session-id is reused across all cloud queries within one diagnostic session so server-side logs can be correlated
The Agent MUST append this --user-agent flag to every aliyun CLI invocation in Step 3.
Prerequisites
-
Python 3.11+ and aliyun CLI - the packaged scripts run on Python 3.11+ with no external SDK dependencies. Cloud queries are invoked directly by the Agent through the aliyun CLI in lowercase-hyphenated plugin mode (e.g. aliyun sas describe-susp-events); no direct HTTP signing.
-
Alibaba Cloud credentials - credentials are resolved automatically by the aliyun CLI default credential chain (environment or ~/.aliyun/config.json). Never read, print, or pass AK/SK/STS tokens explicitly.
-
Inputs: URL (required - the page to scan) and UID (optional - the Alibaba Cloud account UID). UID can be omitted: it is auto-derived from the caller account via aliyun sts get-caller-identity. Auto-fill first, ask second: never ask the user for the UID when it can be derived.
Domain-only input: if the user provides only a domain name, scan the site root (https://<domain>/) and declare this normalization in the report's "Information Sources" section. Do not invent deeper paths.
Auto-fill declaration requirement: whenever any parameter is auto-filled (UID, domain, or any value not explicitly provided by the user), the Agent MUST declare this in the final report, e.g. "UID auto-derived via sts:GetCallerIdentity: 1234567890123456". This declaration is mandatory and appears in the "Information Sources (mandatory)" section of the report; see references/report-template.md.
Authentication: Identity Verification
python3 scripts/sts_token.py --json
sts_token.py only performs identity verification (via aliyun sts get-caller-identity) and UID derivation. Credentials for all subsequent cloud queries always come from the aliyun CLI default credential chain.
Identity verification failure: if sts_token.py fails, the caller lacks valid credentials/permissions. Guide the user to authorize via the RAM console using the least-privilege policy in references/ram-policies.md. The local scan steps (Step 1 / Step 2) require no cloud permissions and can proceed regardless.
Diagnostic Flow
Three-level routing: Step 1 static scan -> Step 2 cloaking detection -> Step 3 cloud corroboration -> report.
User reports defacement / hijacking / abnormal redirect
|
v
Step 1: static scan (website_malware_check.py --mode static)
|
|-- malicious evidence found -----------------+
|-- redirect suspected / UA or device diff --> Step 2: multi-UA matrix
|-- clean, but user insists on a redirect --> --mode source deep dive
(external JS scan)
+---------------------------------------------+
v
Step 3: cloud corroboration (SAS / WAF, best-effort;
403 or empty result -> declare skip, continue)
v
Step 4: report per references/report-template.md
Step 1: Static Scan
python3 scripts/website_malware_check.py <url> --mode static [--json] [--timeout 60]
Static mode fetches the page with a normal browser User-Agent and with a search-engine User-Agent, then checks for hidden links, redirect declarations, hidden iframes, suspicious external scripts/links, and UA divergence.
| Result | Next Step |
|---|
| Malicious code / hidden links / redirect found | Classify the injection per references/injection-types.md, then Step 3 for corroboration, then report |
| Redirect suspected, or user reports device/UA differences | Step 2 |
| Nothing found but the user insists a redirect exists | Deep dive: python3 scripts/website_malware_check.py <url> --mode source fetches all external JS files, scans them with the suspicious-keyword library, and extracts malicious code blocks; then Step 3 |
Step 2: Cloaking Detection (Multi-UA Matrix)
Use when the user reports device-specific behavior ("mobile redirects but desktop is fine", "redirect after refresh", "redirect only inside the in-app browser") or Step 1 hints at UA divergence.
python3 scripts/multi_ua_probe.py matrix <url> [--workers N] [--format json|markdown] [--timeout 30]
The matrix fetches the URL with desktop / mobile / in-app / search-engine User-Agents crossed with no-referer and external-search referers (mobile UA + external referer is the classic cloaking trigger), and flags every variant whose body diverges from the desktop baseline or contains redirect code. To inspect one suspicious combination in detail:
python3 scripts/multi_ua_probe.py fetch <url> --ua <name> [--referer <name>] [--format json|markdown]
| Result | Next Step |
|---|
| Some UA+Referer variants return different or malicious content | Server-side cloaking confirmed; record the exact trigger matrix in the report, then Step 3 |
| All variants identical to the baseline | No cloaking observed at probe time; proceed to Step 3 and state this in the report |
Special Case: Redirect Only After Refresh
When the user reports "the redirect only appears after I refresh the page", a single probe of the target URL is not enough:
- Simulate the full visit -> refresh flow: request the URL once with no Referer, then request it again with the URL itself as Referer, and once more with an external search Referer - reusing the same cookie jar across requests.
- If the three responses differ, the hijack is cookie/session-gated or refresh-triggered conditional injection; record which combination triggers it.
- If all three responses look clean but the user still sees the redirect, check for directory-level hijacking below.
Special Case: Directory-Level (Wildcard) Hijacking
Some hijacks configure a wildcard rule (e.g. a URL Rewrite rule or handler on IIS) that intercepts every request in a directory that does not map to a physical file and returns malicious content. The user's target URL may happen to be a real static file and look completely clean. Signals:
- Sibling URLs in the same directory all return the same tiny payload (e.g. a one-line malicious
<script> tag).
- A guaranteed-nonexistent URL in that directory returns
200 with the same malicious content instead of 404.
- Hijacked responses are generated dynamically: no
ETag / Last-Modified, unlike the full cache headers of genuine static files.
Verify by probing several sibling URLs plus one nonexistent URL in the same directory (python3 scripts/website_malware_check.py <sibling-url> --mode static or python3 scripts/multi_ua_probe.py fetch), then compare response sizes and cache headers.
Step 3: Cloud Corroboration (best-effort, read-only)
Cloud lookups corroborate local findings. They are strictly best-effort: the caller role may receive a 403 no-permission error (error code NoPermission) for SAS/WAF read-only APIs, and WAF may return empty results when the account has no protected domain onboarded. On any error, empty result, or service-not-enabled response, record the skip reason in the report and continue - a cloud query failure must never abort the diagnosis.
MANDATORY execution discipline: Step 3 MUST be carried out by executing the aliyun CLI read-only queries below directly (never through a wrapper script, and never skipped). Execute all four queries in order - one Security Center suspicious-events query, one WAF instance query, one WAF domain-detail query (if the instance ID is unavailable, continue with the fallback instance ID waf-fallback-instance instead of stopping), and one Security Center re-check with a severity filter. When a query returns any error (no permission / invalid parameter / throttling / internal error), record the error code and immediately continue with the next query - do not retry the same command, and never abort the remaining queries.
MANDATORY output-masking discipline: Security Center alert payloads can embed third-party credential strings (leaked AccessKey values, temporary session tokens) inside event fields, and the raw stdout of every command is captured verbatim into the execution transcript - masking them afterwards while writing the report is too late. Therefore every Security Center query MUST be piped through the credential-masking filter shown below; never run the bare command. The filter is a plain in-place output rewrite: it does not redirect stdout/stderr to a file and does not suppress error responses, so API error codes stay directly visible in the terminal output. On top of the filter, never paste a raw cloud API response body into any output, log file, or reply - summarize findings instead, and keep every credential-looking value masked in the final report and in ran_scripts logs.
aliyun sts get-caller-identity --region cn-hangzhou --user-agent AlibabaCloud-Agent-Skills/alibabacloud-website-malware-check/<session-id>
set -o pipefail; aliyun sas describe-susp-events --from sas --current-page 1 --page-size 20 --region cn-hangzhou --user-agent AlibabaCloud-Agent-Skills/alibabacloud-website-malware-check/<session-id> | sed -E 's#(STS\.|LTAI)[A-Za-z0-9+/=_-]{6,}#<credential-masked>#g'
set -o pipefail; aliyun sas describe-susp-events --from sas --levels serious --current-page 1 --page-size 20 --region cn-hangzhou --user-agent AlibabaCloud-Agent-Skills/alibabacloud-website-malware-check/<session-id> | sed -E 's#(STS\.|LTAI)[A-Za-z0-9+/=_-]{6,}#<credential-masked>#g'
aliyun waf-openapi describe-instance --biz-region-id cn-hangzhou --user-agent AlibabaCloud-Agent-Skills/alibabacloud-website-malware-check/<session-id>
aliyun waf-openapi describe-domain-detail --instance-id <id> --domain <domain> --biz-region-id cn-hangzhou --user-agent AlibabaCloud-Agent-Skills/alibabacloud-website-malware-check/<session-id>
| Cloud result | Handling |
|---|
| Alerts or WAF records found | Cite them as corroborating evidence in the report |
403 no-permission error (NoPermission) | Declare "cloud corroboration skipped: caller lacks SAS/WAF read permission" and continue |
| Empty result / service not enabled / no WAF domain | Declare "no SAS alerts found" or "domain not onboarded to WAF" and continue |
Step 4: Output Report
Generate the report per references/report-template.md. The report must contain the "Information Sources (mandatory)" section carrying both the auto-fill declarations and any cloud-corroboration skip reasons. Remediation advice follows references/remediation-guide.md.
When malicious code is located, the report must also include an attack chain reconstruction: how the page loads the malicious resource (which template line / external script / server rule), what the malicious code does (trigger conditions such as time-of-day, probability, cookie gating), and the exact element to remove. This is what makes the remediation actionable for the site owner.
Constraints
- Read-only operations: the skill only fetches/analyzes pages and queries cloud services; it never modifies the target website and performs no write operations anywhere.
- Timeouts on every network call: page fetches, multi-UA probes, and cloud queries all run with explicit timeouts; no unbounded waits.
- No credentials in output: reports, execution transcripts, and ran_scripts logs never contain AK/SK, session tokens, or any credential material - including credential strings embedded inside cloud API response data (e.g. leaked-AK fields in Security Center alerts), which are stripped at the command level by the masking filter in Step 3 rather than after the fact.
- Probe restraint: multi-UA probes send a small, bounded number of requests (the fixed matrix combinations only) to avoid load on the target site.
- Local-only fallback: if cloud permissions are unavailable or the services are not enabled, the skill still completes the local detection steps and produces the full report; cloud corroboration is simply declared skipped.
Available Scripts
| Script | Purpose |
|---|
scripts/website_malware_check.py | Static defacement scan and JS source deep dive (--mode static / --mode source) |
scripts/multi_ua_probe.py | Multi-UA / Referer matrix probe for cloaking detection (matrix / fetch) |
scripts/sts_token.py | Identity verification and UID derivation |
Error Handling
Absolute Rule: on any error, record the error and its error code, continue the remaining diagnostic steps, and state the error in the final report - never swallow errors silently and never abort the whole diagnosis because one step failed.