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 · 23 · 0 current installs · 0 all-time installs
MIT-0
Security Scan
VirusTotalVirusTotal
Suspicious
View report →
OpenClawOpenClaw
Benign
high confidence
Purpose & Capability
Name/description (static website deploy to AIOZ Storage) align with required binaries (node, npx, curl), the curl-based login to api.aiozstorage.network, cloning the official examples repo, and the included grant-cli.ts which generates grants for AIOZ buckets.
Instruction Scope
SKILL.md explicitly asks users for AIOZ email/password and instructs storing the resulting bearer token/accountId and running the included grant-cli.ts to create grants and register S3 credentials, then upload files. This stays within deploy workflow, but is somewhat vague about where/how tokens are stored and how long they persist; the agent/runner could inadvertently persist secrets if not handled carefully. The instructions also ask the agent/user to run local code (grant-cli.ts) which executes cryptographic operations — expected for the task, but worth manual review before execution.
Install Mechanism
There is no formal install spec (instruction-only skill), but the package contains a TypeScript CLI (grant-cli.ts) and package.json. The workflow expects running npx ts-node grant-cli.ts which will execute the bundled TypeScript. This is a reasonable approach for this purpose, but executing code via npx/ts-node can fetch or run code at runtime; review the bundled grant-cli.ts before running and prefer running it in a controlled environment.
Credentials
The skill requests no unrelated environment variables or external credentials. It legitimately asks the user for their AIOZ email/password and the per-bucket passphrase(s) required by the service; those inputs are appropriate for creating grants and uploading content.
Persistence & Privilege
Skill does not request always:true, does not declare system-wide config paths, and does not modify other skills. Autonomous invocation is allowed (platform default) but is not combined with elevated privileges here.
Assessment
This skill appears to do what it says: log in to AIOZ, prepare a template or custom site, generate a grant with the included grant-cli.ts, and upload files. Before installing or running it: 1) Manually inspect grant-cli.ts (it is bundled) to confirm its behavior (it performs local crypto and protobuf encoding — expected). 2) Run the CLI in a sandbox or on a throwaway AIOZ account if you want to avoid exposing your primary credentials. 3) Be explicit about where you store the BEARER_TOKEN/ACCOUNT_ID (avoid saving to persistent global agent state unless you intend that). 4) Because the workflow uses npx ts-node, ensure your environment is trusted or pre-install required tools to avoid unexpected network fetches. If you are uncomfortable entering your real AIOZ password, create a temporary account with limited access for testing.
!
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.1
Download zip
latestvk970jnv2b1wchd6a3taybzsh3x8309s6

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…