# Alibabacloud Website Malware Check

> 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".

- Skill: `aliyun/alibabacloud-website-malware-check` (Agent Skill, multi-file: 10 files)
- Install (CLI): `npx skillmds@latest add aliyun/alibabacloud-website-malware-check`
- Raw SKILL.md: https://api.skillmd.com/api/skills/aliyun/alibabacloud-website-malware-check/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Marketing & Growth
- Author: aliyun (https://skillmd.com/u/aliyun)
- Updated: 2026-09-09
- Page: https://skillmd.com/skills/aliyun/alibabacloud-website-malware-check

---


# 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:

1. **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.
2. **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.
3. **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](references/detection-capabilities.md). Injection classification is defined in [references/injection-types.md](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

1. **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.
2. **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.
3. **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](references/report-template.md).

## Authentication: Identity Verification

```bash
# Verify caller identity and derive the caller UID.
# The script performs identity verification only - it does not carry,
# print, or pass any credential.
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](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

```bash
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](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.

```bash
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:

```bash
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:

1. 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.
2. If the three responses differ, the hijack is cookie/session-gated or refresh-triggered conditional injection; record which combination triggers it.
3. 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.

```bash
# Caller identity / UID derivation
aliyun sts get-caller-identity --region cn-hangzhou --user-agent AlibabaCloud-Agent-Skills/alibabacloud-website-malware-check/<session-id>

# Security Center: list suspicious events (alerts) on the account.
# The trailing sed is the MANDATORY credential-masking filter - keep it on
# every SAS query, including the severity re-check below. `set -o pipefail`
# keeps the aliyun exit status visible through the pipe, so API errors are
# still detected normally.
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'

# Security Center re-check narrowed by severity (the fourth query)
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'

# WAF: locate the instance first, then query domain access detail
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](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](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.

