saw-web-target-configuration — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited saw-web-target-configuration (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
Configure web application targets for Snyk API & Web security scanning with authentication support. For API targets, use the saw-api-target-configuration skill instead.
Login sequences require a real browser. Detect availability in this order:
playwright-cli (preferred for coding agents with Shell access)playwright-cli --version
# or: npx @playwright/cli --versionIf missing, install (no repo clone required):
npm install -g @playwright/cli@latest
playwright-cli install-browser chromiumOr, when a clone of this repo is available:
./scripts/setup-playwright.shUse `npx @playwright/cli` instead of playwright-cli when the global binary is not on PATH.
Check whether Playwright MCP tools are available (e.g. browser_navigate, browser_snapshot, browser_evaluate, browser_network_requests).
If missing, tell the user to install Playwright MCP:
{
"mcpServers": {
"playwright": {
"command": "npx",
"args": ["-y", "@playwright/mcp@latest"]
}
}
}Or install Playwright from the Cursor Marketplace.
If neither path works and the user cannot install one:
playwright-cli (preferred) or Playwright MCP.Never guess CSS/XPath selectors without browser inspection.
Before proceeding, determine whether this is an API target or a web target:
saw-api-target-configuration skill instead.When you finish adding/configuring a target, always summarize it with a table, and include a link to the target on Snyk API & Web. Use the Snyk API & Web app URL https://plus.probely.app. Include a column if you added extra hosts or not and in case you did, which ones.
When the user provides more than one target, launch a subagent per target.
| Browser path | Subagent concurrency |
|---|---|
| `playwright-cli` | Subagents may run in parallel — each MUST use a globally unique session name: playwright-cli -s=<session>. Do NOT use the bare domain, since multiple targets can share one hostname (duplicate-URL flows, multiple accounts on one app) and would collide into a shared browser context. Use <domain>-<targetIndex> (e.g. app.example.com-1, app.example.com-2), appending the account/username when several targets share a domain. |
| Playwright MCP | Subagents must run one at a time — Playwright MCP uses a single shared browser instance |
Each subagent prompt should be short — just the target details and an instruction to read the skill file:
Configure a Snyk API & Web web target:
- URL: <url>
- Name: <name or "auto" — if "auto", derive from the site's <title>>
- Labels: <["Label1", ...] or "default" — if "default", do NOT pass labels param>
- Username: <user>
- Password: <pass>
- 2FA TOTP seed: <seed or "none">
- Browser session name: <session> (playwright-cli only — a globally unique name such as `<domain>-<targetIndex>`, plus the account/username when targets share a domain; use with `playwright-cli -s=<session>` for ALL browser commands)
First read the skill file at <ABSOLUTE_PATH_TO_THIS_SKILL_FILE> and follow the full workflow.
Return a summary with: target ID, name, URL, login sequence status, logout detection status, extra hosts, Snyk API & Web link (https://plus.probely.app/targets/{targetId}).After all subagents finish, compile summaries into one table.
Use the credential manager for sensitive values (passwords, TOTP seeds, etc.) by default. Store values via probely_create_credential with is_sensitive=True and use the returned uri (e.g. credentials://xxxx) in the API. If the user explicitly declines, inline values are allowed.
When configuring multiple targets that use the same credentials, the credential may already exist in the credential manager from a previous target. Since sensitive (obfuscated) values cannot be read back, the agent cannot verify whether it matches — this causes a new credential entry per target, polluting the credential manager.
Rule: When multiple targets share the same credential and it already exists with is_sensitive=True, prompt the user to deobfuscate it (update to is_sensitive=False via probely_update_credential) so it can be read back and reused across targets. Inform the user why deobfuscation is needed.
Workflow for shared credentials:
is_sensitive=True for the first target.probely_list_credentials.is_sensitive=True or value is null), prompt the user: "The credential '<name>' is obfuscated. To reuse it across multiple targets, it needs to be deobfuscated. Would you like to proceed?"probely_update_credential(credentialId, is_sensitive=False).uri for the new target.Pattern:
cred = probely_create_credential(
name="<target_name> - <description>",
value="the_actual_secret_value",
is_sensitive=True
)
# cred["uri"] → "credentials://xxxx"Credential URIs: Use the format credentials://<credential_id> (e.g., credentials://4DY4qGohso1r). Get credential URIs from probely_list_credentials or probely_create_credential. Do NOT use template syntax like `{{cred-name}}`.
playwright-cli only)Each target MUST use a globally unique named session (-s=<session>) for fully isolated browser context (separate cookies, storage, network logs). Never reuse the bare <domain> as the session name: multiple targets can share a hostname (duplicate-URL flows, multiple accounts on one app), and colliding names make parallel subagents share one browser context. Build the name from the domain plus a discriminator, e.g. <domain>-<targetIndex> or <domain>-<username> (such as app.example.com-alice, app.example.com-bob).
playwright-cli only)The Shell tool defaults to a 30-second timeout (block_until_ms: 30000), which is often too short for browser automation.
ALWAYS set `block_until_ms: 60000` on Shell calls that run `playwright-cli`. For slow targets/pages, use block_until_ms: 90000.
Ask the user for (or derive):
<title> > FQDN)Authentication method (in order):
#### Creating Duplicate Targets
To create a duplicate target (same URL as existing target), use allow_duplicate=True. This is useful when you want multiple targets for the same URL with different configurations (e.g., different authentication methods, different test scenarios):
probely_create_web_target(
name="MyApp - Different Auth Method",
url="https://app.example.com",
allow_duplicate=True,
)#### Reachability Failures
If target creation fails because the target is unreachable or the domain cannot be resolved, do not stop at the first error. Ask the user whether you should retry with skip_reachability_check=True. Only retry after the user explicitly agrees.
playwright-cli (preferred)Use playwright-cli via the Shell tool. Set block_until_ms: 60000 (or 90000 for slow pages).
playwright-cli -s=SESSION open <url>snapshot and goto.scripts/inspect-login-form.js via playwright-cli -s=SESSION eval '<js>'. Repeat on every login step. If it returns step: "canvas" (or a canvas field with submit: null), the fields/button are painted on a <canvas> (a canvas-rendered login, e.g. Flutter web) — read the page <script> or take a screenshot to find the field/button rectangles and use bclick/bfill_value with coordinates. See references/sequence-format.md → Canvas-Rendered Logins. If it returns step: "shadow_dom" (fields inside open shadow roots), use the inner-element selector it reports (e.g. input[type="password"]) with the attribute-based xpath it reports (a real XPath that pierces the shadow root, e.g. //input[@type='password']; /html/node/shadow is only a fallback) — never a host input piercing selector. Shadow roots are isolated scopes, so inner elements can share id/name/type: ensure each selector/XPath is unique across all shadow roots (heed any ambiguous/warning in the output). See references/sequence-format.md → Shadow DOM Inputs.snapshot to get element refs, then fill and click. Refs (e.g. e15) or unique CSS selectors both work. If clicking the login trigger opens a popup window (a new tab appears — e.g. from window.open(...)), switch to it with playwright-cli -s=SESSION tab-select <index> before inspecting/filling, and add "allow_popups": true to the first goto step of the sequence. See references/sequence-format.md → Popup-Based Logins.probely_generate_totp for the live OTP, then fill the OTP field.eval '() => window.location.href').eval.references/extra-hosts.md; run playwright-cli -s=SESSION requests at pre/post-login checkpoints.references/sequence-format.md.playwright-cli -s=SESSION closeThen apply SAW configuration (Step 3).
Use when playwright-cli is unavailable but Playwright MCP tools exist.
browser_navigatescripts/inspect-login-form.js via browser_evaluate on every login step. If it returns step: "canvas" (or a canvas field with submit: null), the fields/button are painted on a <canvas> (a canvas-rendered login, e.g. Flutter web) — read the page <script> or take a screenshot to find the field/button rectangles and use bclick/bfill_value with coordinates. See references/sequence-format.md → Canvas-Rendered Logins. If it returns step: "shadow_dom" (fields inside open shadow roots), use the inner-element selector it reports (e.g. input[type="password"]) with the attribute-based xpath it reports (a real XPath that pierces the shadow root, e.g. //input[@type='password']; /html/node/shadow is only a fallback) — never a host input piercing selector. Shadow roots are isolated scopes, so inner elements can share id/name/type: ensure each selector/XPath is unique across all shadow roots (heed any ambiguous/warning in the output). See references/sequence-format.md → Shadow DOM Inputs.window.open(...)), switch to it (browser_tabs/select the new page) before inspecting/filling, and add "allow_popups": true to the first goto step of the sequence. See references/sequence-format.md → Popup-Based Logins.probely_generate_totp for the live login.browser_evaluate.references/extra-hosts.md; use browser_network_requests() at pre/post-login checkpoints.references/sequence-format.md.Then apply SAW configuration (Step 3).
target = probely_create_web_target(
name=..., url=..., desc=..., labels=...
) # use target["id"] as targetId
# If 2FA: call probely_configure_2fa_totp BEFORE creating the sequence (use otp_code in sequence JSON)
probely_create_credential(...) # password — link via custom_field_mappings
# The first "goto" step of the sequence content MUST include "powered_by": "saw mcp"
probely_create_sequence(
targetId,
name="Login Sequence",
content="...",
sequence_type="login",
enabled=True,
custom_field_mappings=[...],
)
probely_configure_sequence_login(targetId, enabled=True)
# See references/logout-detection.md
probely_configure_logout_detection(
targetId,
enabled=True,
check_session_url=...,
logout_detector_type=...,
logout_detector_value=...,
logout_condition=...,
)
# See references/extra-hosts.md
probely_create_extra_host(targetId, hostname="...", ip_address="")Use only when neither playwright-cli nor Playwright MCP is available, or the user explicitly accepts the limitation (no multi-step login, no 2FA).
By default, store the password via credential manager and pass the credential URI. If the user explicitly declines, pass the password inline.
probely_configure_form_login(
targetId,
login_url="https://app.example.com/login",
username_field="email",
password_field="password",
username="[email protected]",
password="...", # inline or cred URI
check_pattern="Welcome",
)~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.