Skill flagged — suspicious patterns detected

ClawHub Security flagged this skill as suspicious. Review the scan results before using.

AIOZ Storage Skill

Deploy static websites to AIOZ Storage with built-in templates or custom sites.

MIT-0 · Free to use, modify, and redistribute. No attribution required.
0 · 31 · 0 current installs · 0 all-time installs
MIT-0
Security Scan
VirusTotalVirusTotal
Suspicious
View report →
OpenClawOpenClaw
Benign
high confidence
Purpose & Capability
Name/description (deploy static sites to AIOZ Storage) match the included artifacts: SKILL.md describes login, template cloning, grant generation, S3 upload and API calls. Required binaries (node, npx, curl) are reasonable for the described flow. The grant-cli.ts implements the grant generation referenced in the flow and is appropriate for the skill's purpose.
Instruction Scope
Instructions explicitly ask the user for AIOZ email/password, bucket passphrases and to fetch rootZKey from the AIOZ API — these are sensitive but required for the service. The SKILL.md confines actions to cloning the GitHub templates, calling the AIOZ API (api.aiozstorage.network), generating grants with the included script, and uploading to S3 — there are no instructions to read unrelated system files or send data to unexpected endpoints. Verify you trust the AIOZ service before providing credentials.
Install Mechanism
There is no install spec; the skill includes grant-cli.ts and a package.json. The recommended invocation uses 'npx ts-node grant-cli.ts', which will cause npx to fetch ts-node if it's not already present. Fetching tools via npx/npm is common here but carries transient supply-chain risk — expected for running a TypeScript script but worth noting.
Credentials
The skill requests no environment variables or unrelated credentials. It does prompt for service-specific secrets (email/password, passphrases, rootZKey/accountId) that are necessary for creating and registering grants and buckets on AIOZ; these are proportionate to the task.
Persistence & Privilege
The skill is not always-enabled and doesn't request system-wide configuration or persistent privileges. It does include a local CLI script (grant-cli.ts) which the agent may run during a session; that is normal and limited in scope to grant creation.
Assessment
This skill appears to do what it says: it will ask you for your AIOZ account email/password, bucket passphrases and rootZKey/accountId so it can create grants and upload site files. Before installing or running it: (1) confirm you trust the AIOZ service and the upstream GitHub templates, (2) avoid reusing high-value passwords — use an account or credentials you can revoke if needed, (3) be aware that using 'npx ts-node' will fetch tooling from the npm registry if ts-node isn't present (run in an isolated environment if you are concerned), and (4) if you have concerns, inspect/execute grant-cli.ts in a sandbox or translate it to a pre-built JS file so you don't rely on npx to pull runtime deps. Overall the skill is internally consistent and not exhibiting hidden/excessive behavior, but handle the requested credentials cautiously.
!
grant-cli.ts:586
File read combined with network send (possible exfiltration).
About static analysis
These patterns were detected by automated regex scanning. They may be normal for skills that integrate with external APIs. Check the VirusTotal and OpenClaw results above for context-aware analysis.

Like a lobster shell, security has layers — review code before you run it.

Current versionv1.0.0
Download zip
latestvk9770p4540xc6n70rnhzhmhqad8310nx

License

MIT-0
Free to use, modify, and redistribute. No attribution required.

Runtime requirements

OSLinux · macOS
Binsnode, npx, curl

SKILL.md

AIOZ Static Website Deploy

Deploy a static website to AIOZ decentralized storage. Supports 4 built-in templates or user's own static site.

FLOW OVERVIEW

1. Login (email + password) → Bearer token + accountId
2. Choose template or custom site
3. Clone template & customize CONFIG
4. Get bucket info (name + 12-word passphrase)
5. Get rootZKey from API
6. Generate grant via grant-cli.ts
7. Register S3 credentials from grant
8. Upload files to S3
9. Create static website via API
10. Site live at https://<bucket>.sites.aiozstorage.app

STEP 1: LOGIN

Ask user for AIOZ Storage email and password.

curl -s 'https://api.aiozstorage.network/api/v1/login' \
  -H 'accept: application/json' \
  -H 'content-type: application/json' \
  -H 'origin: https://aiozstorage.network' \
  -H 'referer: https://aiozstorage.network/' \
  --data-raw '{"email":"<EMAIL>","password":"<PASSWORD>"}'

Response: data.access_token (Bearer token), data.account.id (accountId). Store BEARER_TOKEN and ACCOUNT_ID.

STEP 2: CHOOSE TEMPLATE

Ask user which template or if they have their own static site.

Templates from https://github.com/AIOZStorage/aioz-storage-docs/tree/main/examples:

  1. landing — OLED dark theme, X/Twitter style landing page. CONFIG in assets/main.js.
  2. landing-alt — Purple gradient landing page. CONFIG in assets/main.js. Supports *italic* gradient text in headlines.
  3. portfolio — Clean minimal portfolio for devs/designers. CONFIG in assets/main.js. Image carousel for projects.
  4. documents — Full documentation site with Markdown content. CONFIG in assets/js/config.js. Search, TOC, syntax highlighting.
  5. Custom — User provides their own static files.

STEP 3: CLONE TEMPLATE & CUSTOMIZE

Clone the chosen template:

git clone --depth 1 https://github.com/AIOZStorage/aioz-storage-docs.git /tmp/aioz-storage-docs
cp -r /tmp/aioz-storage-docs/examples/<template_name> ./<project_folder>

Then customize the CONFIG object based on template type:

Template: landing

Config: assets/main.jsCONFIG object. Theme: "dark" (OLED black) or "light".

Key fields to customize:

  • brand.name — brand/product name
  • meta.title, meta.description — SEO
  • hero.eyebrow — pill badge (or null to hide), hero.title, hero.sub
  • hero.primaryCta{ label, href }, hero.secondaryCta
  • sections.* — toggle: highlights, logos, features, useCases, testimonials, pricingTop, pricingBot, faq
  • highlights[]{ number, label } stats (numbers animate on scroll)
  • logos.items[] — company name strings
  • features{ label, title, sub, items: [{ title, desc }] }
  • useCases{ label, title, sub, items: [{ tag, title, desc }] }
  • testimonials[]{ quote, name, role, company, avatar: { initials, bg } }
  • pricing.plans[]{ name, price, period, desc, isPopular, cta: { label, href }, features[] }
  • faq.items[]{ q, a }
  • cta.form.mode"redirect" | "mailto" | "webhook"
  • footer.brandDesc, footer.columns[], footer.socials[]
  • Colors in assets/style.css :root--color-primary: #1d9bf0

Template: landing-alt

Config: assets/main.jsCONFIG object. Theme: "light" | "dark" | "system".

Key fields to customize:

  • brand.name, brand.tagline
  • hero.badge — pill badge (or null), hero.headline (wrap words in *asterisks* for gradient italic text), hero.subheadline
  • hero.primaryCta, hero.secondaryCta, hero.ctaNote
  • sections.* — toggle: stats, problemSolution, features, useCases, logos, testimonials, pricing, faq
  • stats[]{ number, label } (numbers animate on scroll)
  • problemSolution{ problem: { label, title, items[] }, solution: { label, title, items[] } }
  • features.items[]{ size, gradient, kicker, title, desc, tag, visual } (bento grid, size: "wide"|"narrow"|"half"|"third"|"full")
  • pricing.plans[]{ name, price, period, desc, isPopular, cta, features[] }
  • cta.form.mode"redirect" | "mailto" | "webhook"
  • Colors in assets/style.css--color-primary: #635bff, --color-gradient-start, --color-gradient-end

Template: portfolio

Config: assets/main.jsCONFIG object. Theme: "light" | "dark" | "auto".

Key fields to customize:

  • personal.firstName, personal.lastName, personal.title, personal.email
  • personal.location{ city, country }
  • about.subtitle, about.bio (array of paragraphs), about.focusAreas (array of skill strings)
  • experience[]{ company, tagline, period, position, description, longDescription, location, industry, website: { label, url } }
  • projects[]{ title, tags[], year, images[], description, techNote, link: { label, url } } (multiple images = carousel)
  • social[]{ platform, url }
  • theme.defaultMode, theme.showToggle
  • sections — toggle: showAbout, showExperience, showProjects, showFocusAreas
  • footer.cta, footer.copyright (null = auto-generate)
  • meta.title, meta.description, meta.ogImage
  • Images in assets/images/ (1600×900 for projects, 1200×630 for OG)

Template: documents

Config: assets/js/config.jsCONFIG object. Theme: "light" | "dark" | "auto".

Key fields to customize:

  • site.title, site.description, site.version
  • site.logo.light, site.logo.dark
  • sidebar[]{ group, collapsed, items: [{ label, path }] } (path = filename without .md)
  • header.nav[]{ label, href }, header.links[]{ icon, href }
  • footer.copyright, footer.columns[]
  • features — toggle: search, tableOfContents, feedback, prevNext, copyCodeButton, scrollToTop
  • features.editLink{ enabled, baseUrl, text }
  • features.tocDepth — 2 or 3

Content: create .md files in /docs/ with YAML front matter:

---
title: Page Title
description: Brief description
order: 1
hidden: false
---

Callouts: > [!NOTE], > [!TIP], > [!WARNING], > [!DANGER] Code blocks with syntax highlighting (javascript, typescript, python, bash, json, html, css, yaml, sql, go, rust, java, etc.) Hash routing: index.html#/page-name → loads docs/page-name.md

STEP 4: GET BUCKET INFO

Ask user for:

  1. Bucket name — their bucket on aiozstorage.network
  2. 12-word seed phrase — BIP39 passphrase from bucket creation

IMPORTANT: AIOZ Storage does NOT store passphrases. If lost, bucket access is lost forever.

See: https://aiozstorage.network/docs/tutorials/manage-buckets

STEP 5: GET ROOT ZKEY

curl -s 'https://api.aiozstorage.network/api/v1/zkeys' \
  -H 'accept: application/json' \
  -H 'content-type: application/json' \
  -H 'authorization: Bearer <BEARER_TOKEN>' \
  -H 'origin: https://aiozstorage.network' \
  -H 'referer: https://aiozstorage.network/' \
  --data-raw '{"name":"deploy-key","force":true}'

Extract: ROOT_ZKEY = data.zkey

STEP 6: GENERATE GRANT

Prerequisites (one-time setup in {baseDir})

cd {baseDir} && npm install

This installs argon2-browser and ts-node. No build:sjcl needed — the CLI uses Node.js built-in crypto.

Run grant-cli.ts (RECOMMENDED: JSON output for bot)

Two grants are needed:

  1. Upload grant — permissions 1,2,3 (Read+Write+List) for S3 upload
  2. Website grant — permissions 1,3 (Read+List only) for website creation

Upload grant:

npx ts-node {baseDir}/grant-cli.ts \
  --mode per-bucket \
  --zkey "<ROOT_ZKEY>" \
  --account "<ACCOUNT_ID>" \
  --url w3s \
  --duration 0 \
  --bucket "<BUCKET_NAME>" \
  --passphrase "<12_WORD_SEED_PHRASE>" \
  --permissions 1,2,3 \
  --output json \
  --quiet

Website grant:

npx ts-node {baseDir}/grant-cli.ts \
  --mode per-bucket \
  --zkey "<ROOT_ZKEY>" \
  --account "<ACCOUNT_ID>" \
  --url w3s \
  --duration 0 \
  --bucket "<BUCKET_NAME>" \
  --passphrase "<12_WORD_SEED_PHRASE>" \
  --permissions 1,3 \
  --output json \
  --quiet

Output (single JSON line to stdout):

{"grant":"<GRANT_STRING>","zkey":"<ZKEY_STRING>"}

Parse JSON to extract UPLOAD_GRANT and WEBSITE_GRANT.

IMPORTANT: Website API rejects grants with Write (2) or Delete (4) permissions.

Alternative: config file

echo '{"mode":"per-bucket","rootZKey":"<ROOT_ZKEY>","accountId":"<ACCOUNT_ID>","url":"w3s","duration":0,"buckets":[{"name":"<BUCKET_NAME>","passphrase":"<PASSPHRASE>","permissions":["1","2","3"]}]}' > /tmp/upload-grant-config.json
npx ts-node {baseDir}/grant-cli.ts --config /tmp/upload-grant-config.json --output json --quiet

echo '{"mode":"per-bucket","rootZKey":"<ROOT_ZKEY>","accountId":"<ACCOUNT_ID>","url":"w3s","duration":0,"buckets":[{"name":"<BUCKET_NAME>","passphrase":"<PASSPHRASE>","permissions":["1","3"]}]}' > /tmp/website-grant-config.json
npx ts-node {baseDir}/grant-cli.ts --config /tmp/website-grant-config.json --output json --quiet

CLI flags

FlagRequiredDescription
--modeYesper-bucket or all-buckets
--zkeyYesRoot ZKey (base64url)
--accountYesAccount UUID
--urlNoService URL (default: w3s)
--durationNoms, 0 = no expiry (default: 0)
--bucketper-bucketBucket name
--passphraseYes12-word seed phrase
--permissionsper-bucket1,2,3,4 (1=Read 2=Write 3=List 4=Delete)
--configNoPath to JSON config file
--outputNojson for JSON output
--quietNoSuppress logs, stdout only

STEP 7: REGISTER S3 CREDENTIALS

Use the upload grant (permissions 1,2,3):

curl -s 'https://reg-api.aiozstorage.network/api/v1/access' \
  -H 'accept: application/json' \
  -H 'content-type: application/json' \
  -H 'authorization: Bearer <BEARER_TOKEN>' \
  -H 'origin: https://aiozstorage.network' \
  -H 'referer: https://aiozstorage.network/' \
  --data-raw '{"grant":"<GRANT>","public":false}'

Extract: ACCESS_KEY_ID = data.access_key_id, SECRET_KEY = data.secret_key

STEP 8: UPLOAD FILES TO S3

S3 endpoint: https://s3.aiozstorage.network | Region: us-east-1 | PathStyle: true

Using AWS CLI

AWS_ACCESS_KEY_ID="<ACCESS_KEY_ID>" \
AWS_SECRET_ACCESS_KEY="<SECRET_KEY>" \
aws s3 sync ./<project_folder>/ s3://<BUCKET_NAME>/ \
  --endpoint-url https://s3.aiozstorage.network \
  --region us-east-1

Using Node.js (@aws-sdk/client-s3)

Use S3Client with { region: "us-east-1", endpoint: "https://s3.aiozstorage.network", forcePathStyle: true, credentials: { accessKeyId, secretAccessKey } }. Upload each file with PutObjectCommand, setting correct Content-Type:

.htmltext/html .csstext/css .jsapplication/javascript .jsonapplication/json .svgimage/svg+xml .pngimage/png .jpg/.jpegimage/jpeg .webpimage/webp .icoimage/x-icon .mdtext/markdown .woff2font/woff2 default→application/octet-stream

STEP 9: CREATE STATIC WEBSITE

Use the website grant (permissions 1,3 — Read+List only):

curl -s 'https://api.aiozstorage.app/api/v1/websites' \
  -H 'accept: application/json' \
  -H 'content-type: application/json' \
  -H 'authorization: Bearer <BEARER_TOKEN>' \
  -H 'origin: https://aiozstorage.network' \
  -H 'referer: https://aiozstorage.network/' \
  --data-raw '{
    "bucket_name":"<BUCKET_NAME>",
    "enabled":true,
    "index_document":"index.html",
    "error_document":"404.html",
    "use_default_error":true,
    "error_pages":{},
    "grant":"<WEBSITE_GRANT>"
  }'

IMPORTANT: Website API rejects grants with Write (2) or Delete (4) permissions. Use --permissions 1,3 for this grant.

API domain is api.aiozstorage.app (not .network).

STEP 10: DONE

Site is live at: https://<BUCKET_NAME>.sites.aiozstorage.app

API DOMAINS

  • api.aiozstorage.network — login, zkeys
  • reg-api.aiozstorage.network — S3 credential registration
  • s3.aiozstorage.network — S3 upload endpoint
  • api.aiozstorage.app — static website creation
  • <bucket>.sites.aiozstorage.app — static website URL

ERROR HANDLING

  • Login fails → check email/password
  • ZKey creation fails → Bearer token expired, re-login
  • Grant generation fails → verify rootZKey, accountId, bucket name, passphrase
  • S3 upload fails → check credentials, endpoint, bucket name
  • Website creation fails → check grant, bucket name, Bearer token
  • Site 404 → ensure index.html at bucket root (not in subfolder)

IMPORTANT NOTES

  • grant encodes both authorization (Macaroon/ZKey) and encryption key (EKey from passphrase)
  • Two grants needed: upload grant (permissions 1,2,3) and website grant (permissions 1,3)
  • Website API rejects grants with Write (2) or Delete (4) permissions
  • AIOZ Storage is S3-compatible — any AWS SDK works
  • Bearer tokens expire — re-login on 401
  • grant-cli.ts requires Node.js >= 18
  • argon2-browser WASM loading is auto-patched in the CLI
  • All template asset paths are relative (./assets/...) — works from any base URL
  • For documents template, content is in /docs/*.md with YAML front matter
  • For landing/landing-alt/portfolio, all content is in CONFIG object in assets/main.js

Files

4 total
Select a file
Select a file to preview.

Comments

Loading comments…