Token导航 LogoToken导航

Agent Skill · 研究检索

stash-encryption(隐藏加密)

stash-encryption 用于查找、检索和筛选相关信息,适合在 Codex、Claude、Cursor、Gemini CLI 中需要根据关键词、任务场景或来源线索快速定位候选结果时使用。可结合来源仓库、安装命令和原始 README 继续核验具体用法。安装前建议确认权限范围、维护状态,以及是否会触发联网、命令执行或文件读写。

stash-encryption 是研究检索类 Agent Skill,可用宿主为 Codex、Claude、Cursor、Gemini CLI,通过GitHub 仓库获取,权限为接触敏感数据;许可证信息还不明确,第三方扫描已通过,按安装量在研究检索类的 73,675 个 Skill 里排第 66,577。

总安装 261周安装 11GitHub Stars 138下载 92核验 2026-05-01

安装说明

本站只整理中文说明,不托管安装包,也不代用户安装。
GitHub
许可证
unknown

安装方式

通过对话安装

复制提示词发给支持本地命令或 Skills 的 AI 助手,先确认命令和权限,再让它执行。

请帮我安装这个 Agent Skill:stash-encryption(隐藏加密)
来源仓库:https://github.com/cipherstash/protectjs
仓库路径:skills/stash-encryption
安装命令:
npx skills add https://github.com/cipherstash/protectjs --skill stash-encryption
安装前请先检查当前环境是否支持对应 CLI,并向我确认将要执行的命令、安装目录、联网范围和文件读写权限;确认后再执行。

命令行安装

复制命令到本机终端执行。该命令会通过 npx skills 从第三方来源获取 Skill;本站只展示命令,不托管安装包,也不自动执行。

skills.shnpx skills
npx skills add https://github.com/cipherstash/protectjs --skill stash-encryption

这个 Skill 是做什么的

研究检索类 Skill 主要解决「找资料、核对事实、把来源整理清楚」的问题,通常会让助手先检索再总结。

为 TypeScript/Node.js 项目提供字段级加密解决方案。所有数据在离开应用前完成客户端加密,保障传输与存储安全。支持搜索友好加密,允许对密文进行等值、范围或 JSON 查询。依赖 AWS KMS 托管密钥,需配置 CipherStash Stack 组件集成。

stash-encryption 属于研究检索类 Skill,可作为该场景下的辅助能力补充。

来源仓库内路径:skills/stash-encryption

上手步骤

4 步
  1. 1

    确认自己的宿主工具

    公开资料标注支持 Codex、Claude、Cursor、Gemini CLI;先确认自己用的是其中之一,再按对应工具的 Skills 目录放置。

  2. 2

    拿到安装命令

    可以直接复制的命令是 npx skills add https://github.com/cipherstash/protectjs --skill stash-encryption;命令里的占位符换成自己的路径或密钥再执行。

  3. 3

    安装后重启宿主

    命令执行完要完全退出宿主工具再打开,让新装的 Skill 被重新扫描到,否则列表里可能看不到。

  4. 4

    按最小权限试用

    它需要接触敏感数据,先在测试目录或测试账号里跑,确认没问题再放到正式项目。

常见问题

6 条

stash-encryption 怎么安装?

在终端执行 npx skills add https://github.com/cipherstash/protectjs --skill stash-encryption。装完完全退出宿主工具再打开,让它重新扫描本地 Skill。

stash-encryption 支持哪些 AI 工具?

公开资料标注支持 Codex、Claude、Cursor、Gemini CLI。其他工具只要能读取本地 Skill 目录,一般也能手动放进去,但要自己确认触发方式是否一致。

stash-encryption 需要什么权限?

权限级别是接触敏感数据。该 Skill 可能接触密钥、Token、环境变量或敏感配置,应进入高风险复核队列,默认不自动发布。

stash-encryption 是免费的吗?

公开资料没有标注明确许可证,收费和商用限制都无法确认。正式使用前请到来源仓库核对授权说明。

stash-encryption 用的人多吗?

公开数据是累计安装 261 次,近一周安装 11 次,下载 92 次,GitHub 138 星。这些数字来自第三方目录统计,只能当作热度参考,不代表质量或安全性。

stash-encryption 安全吗?

第三方扫描结果为通过,但这只覆盖已知的静态检查项,不能替代自己读一遍源码和安装命令。

值得选的地方和要先想清楚的地方

值得选的地方

  • 同时适配 4 种工具,换客户端不用重新找替代品。
  • 第三方扫描已通过,常见的高风险行为没有命中。

先想清楚的地方

  • 需要接触敏感数据,装到常用环境前要先评估影响面。
  • 许可证没有明确标注,能不能商用、能不能再分发都不确定。
  • 第三方目录整理,版本更新和行为细节以来源仓库为准。

适不适合你

更适合

  • 已经在用 Codex,想直接扩展它能力的人。
  • 需要处理研究检索类任务、又不想每次都手写提示词的人。

不太适合

  • 环境里有大量密钥、凭证,不方便给第三方 Skill 读取的人。
  • 需要明确授权才能用到公司项目里的场景。
  • 需要厂商级技术支持和 SLA 的生产系统。

研究检索类 Skill 对比

6 个同类
Skill总安装GitHub 星权限许可证扫描
find-skills

寻找技能 · Codex、Claude

31,199,81316,486操作浏览器MIT有提醒
self-improving-agent

自我改进 Agent · OpenClaw

16,464,0023,396接触敏感数据MIT-0通过
soultrace

灵魂追踪 · Codex、Claude

7,588,94412需要联网未明确有提醒
self-improving

自我完善 · OpenClaw

6,829,2841,046需要联网MIT-0通过
microsoft-foundry

微软代工厂 · Codex、Claude

6,614,144764调用外部服务未明确有提醒
stash-encryption

隐藏加密 · 本页

261138接触敏感数据未明确通过

按安装量取同分类前几名;数字来自第三方目录统计,只作热度参考,不代表质量结论。

SKILL.md 原文

CipherStash Stack - Encryption

Comprehensive guide for implementing field-level encryption with @cipherstash/stack. Every value is encrypted with its own unique key via ZeroKMS (backed by AWS KMS). Encryption happens client-side before data leaves the application.

When to Use This Skill

  • Adding field-level encryption to a TypeScript/Node.js project
  • Defining encrypted table schemas
  • Encrypting and decrypting individual values or entire models
  • Implementing searchable encryption (equality, free-text, range, JSON queries)
  • Bulk encrypting/decrypting large datasets
  • Implementing identity-aware encryption with JWT-based lock contexts
  • Setting up multi-tenant encryption with keysets
  • Migrating from @cipherstash/protect to @cipherstash/stack

Installation

npm install @cipherstash/stack

The package includes a native FFI module (@cipherstash/protect-ffi). You must opt out of bundling it in tools like Webpack, esbuild, or Next.js (serverExternalPackages).

Configuration

Environment Variables

Set these in .env or your hosting platform:

CS_WORKSPACE_CRN=crn:ap-southeast-2.aws:your-workspace-id
CS_CLIENT_ID=your-client-id
CS_CLIENT_KEY=your-client-key
CS_CLIENT_ACCESS_KEY=your-access-key

Sign up at cipherstash.com/signup to generate credentials.

Programmatic Config

const client = await Encryption({
  schemas: [users],
  config: {
    workspaceCrn: "crn:ap-southeast-2.aws:your-workspace-id",
    clientId: "your-client-id",
    clientKey: "your-client-key",
    accessKey: "your-access-key",
    keyset: { name: "my-keyset" }, // optional: multi-tenant isolation
  },
})

If config is omitted, the client reads CS_* environment variables automatically.

Logging

Logging is enabled by default at the error level. Configure the log level with the STASH_STACK_LOG environment variable:

STASH_STACK_LOG=error  # debug | info | error (default: error)
ValueWhat is logged
errorErrors only (default)
infoInfo and errors
debugDebug, info, and errors

When STASH_STACK_LOG is not set, the SDK defaults to error (errors only).

The SDK never logs plaintext data.

Subpath Exports

Import PathProvides
@cipherstash/stackEncryption function, Secrets class, encryptedTable, encryptedColumn, encryptedField (convenience re-exports)
@cipherstash/stack/schemaencryptedTable, encryptedColumn, encryptedField, schema types
@cipherstash/stack/identityLockContext class and identity types
@cipherstash/stack/secretsSecrets class and secrets types
@cipherstash/stack/drizzleencryptedType, extractEncryptionSchema, createEncryptionOperators for Drizzle ORM
@cipherstash/stack/supabaseencryptedSupabase wrapper for Supabase
@cipherstash/stack/dynamodbencryptedDynamoDB helper for DynamoDB
@cipherstash/stack/encryptionEncryptionClient class, Encryption function
@cipherstash/stack/errorsEncryptionErrorTypes, StackError, error subtypes, getErrorMessage
@cipherstash/stack/clientClient-safe exports: schema builders, schema types, EncryptionClient type (no native FFI)
@cipherstash/stack/typesAll TypeScript types

Schema Definition

Define which tables and columns to encrypt using encryptedTable and encryptedColumn:

import { encryptedTable, encryptedColumn } from "@cipherstash/stack/schema"

const users = encryptedTable("users", {
  email: encryptedColumn("email")
    .equality()         // exact-match queries
    .freeTextSearch()   // full-text / fuzzy search
    .orderAndRange(),   // sorting and range queries

  age: encryptedColumn("age")
    .dataType("number")
    .equality()
    .orderAndRange(),

  address: encryptedColumn("address"), // encrypt-only, no search indexes
})

const documents = encryptedTable("documents", {
  metadata: encryptedColumn("metadata")
    .searchableJson(), // encrypted JSONB queries (JSONPath + containment)
})

Index Types

MethodPurposeQuery Type
.equality(tokenFilters?)Exact match lookups. Accepts an optional array of token filters (e.g., [{kind: 'downcase'}]) for case-insensitive matching.'equality'
.freeTextSearch(opts?)Full-text / fuzzy search'freeTextSearch'
.orderAndRange()Sorting, comparison, range queries'orderAndRange'
.searchableJson()Encrypted JSONB path and containment queries (auto-sets dataType to 'json')'searchableJson'
.dataType(cast)Set plaintext data typeN/A

Supported data types: 'string' (default), 'text', 'number', 'boolean', 'date', 'bigint', 'json'

Methods are chainable - call as many as you need on a single column.

Free-Text Search Options

encryptedColumn("bio").freeTextSearch({
  tokenizer: { kind: "ngram", token_length: 3 },  // or { kind: "standard" }
  token_filters: [{ kind: "downcase" }],
  k: 6,
  m: 2048,
  include_original: true,
})

Type Inference

import type { InferPlaintext, InferEncrypted } from "@cipherstash/stack/schema"

type UserPlaintext = InferPlaintext<typeof users>
// { email: string; age: string; address: string }

type UserEncrypted = InferEncrypted<typeof users>
// { email: Encrypted; age: Encrypted; address: Encrypted }

Client Initialization

import { Encryption } from "@cipherstash/stack"

const client = await Encryption({ schemas: [users, documents] })

The Encryption() function returns Promise<EncryptionClient> and throws on error (e.g., bad credentials, missing config, invalid keyset UUID). At least one schema is required.

// Error handling
try {
  const client = await Encryption({ schemas: [users] })
} catch (error) {
  console.error("Init failed:", error.message)
}

Encrypt and Decrypt Single Values

// Encrypt
const encrypted = await client.encrypt("hello@example.com", {
  column: users.email,
  table: users,
})

if (encrypted.failure) {
  console.error(encrypted.failure.message)
} else {
  console.log(encrypted.data) // Encrypted payload (opaque object)
}

// Decrypt
const decrypted = await client.decrypt(encrypted.data)

if (!decrypted.failure) {
  console.log(decrypted.data) // "hello@example.com"
}

All plaintext values must be non-null. Null handling is managed at the model level by encryptModel and decryptModel.

Model Operations

Encrypt or decrypt an entire object. Only fields matching your schema are encrypted; other fields pass through unchanged.

The return type is schema-aware: fields matching the table schema are typed as Encrypted, while other fields retain their original types. For best results, let TypeScript infer the type parameters from the arguments rather than providing an explicit <User>.

type User = { id: string; email: string; createdAt: Date }

const user = {
  id: "user_123",
  email: "alice@example.com",  // defined in schema -> encrypted
  createdAt: new Date(),       // not in schema -> unchanged
}

// Encrypt model — let TypeScript infer the return type from the schema
const encResult = await client.encryptModel(user, users)
if (!encResult.failure) {
  // encResult.data.email is typed as Encrypted
  // encResult.data.id is typed as string
  // encResult.data.createdAt is typed as Date
}

// Decrypt model
const decResult = await client.decryptModel(encResult.data)
if (!decResult.failure) {
  console.log(decResult.data.email) // "alice@example.com"
}

The Decrypted<T> type maps encrypted fields back to their plaintext types.

Passing an explicit type parameter (e.g., client.encryptModel<User>(...)) still works for backward compatibility — the return type degrades to User in that case.

Bulk Operations

All bulk methods make a single call to ZeroKMS regardless of record count, while still using a unique key per value.

Bulk Encrypt / Decrypt (Raw Values)

const plaintexts = [
  { id: "u1", plaintext: "alice@example.com" },
  { id: "u2", plaintext: "bob@example.com" },
  { id: "u3", plaintext: "charlie@example.com" },
]

const encrypted = await client.bulkEncrypt(plaintexts, {
  column: users.email,
  table: users,
})
// encrypted.data = [{ id: "u1", data: EncryptedPayload }, ...]

const decrypted = await client.bulkDecrypt(encrypted.data)
// Per-item error handling:
for (const item of decrypted.data) {
  if ("data" in item) {
    console.log(`${item.id}: ${item.data}`)
  } else {
    console.error(`${item.id} failed: ${item.error}`)
  }
}

Bulk Encrypt / Decrypt Models

const userModels = [
  { id: "1", email: "alice@example.com" },
  { id: "2", email: "bob@example.com" },
]

const encrypted = await client.bulkEncryptModels(userModels, users)
const decrypted = await client.bulkDecryptModels(encrypted.data)

Searchable Encryption

Encrypt query terms so you can search encrypted data in PostgreSQL.

Single Query Encryption

// Equality query
const eqQuery = await client.encryptQuery("alice@example.com", {
  column: users.email,
  table: users,
  queryType: "equality",
})

// Free-text search
const matchQuery = await client.encryptQuery("alice", {
  column: users.email,
  table: users,
  queryType: "freeTextSearch",
})

// Order and range
const rangeQuery = await client.encryptQuery(25, {
  column: users.age,
  table: users,
  queryType: "orderAndRange",
})

// JSON path query (steVecSelector)
const pathQuery = await client.encryptQuery("$.user.email", {
  column: documents.metadata,
  table: documents,
  queryType: "steVecSelector",
})

// JSON containment query (steVecTerm)
const containsQuery = await client.encryptQuery({ role: "admin" }, {
  column: documents.metadata,
  table: documents,
  queryType: "steVecTerm",
})

If queryType is omitted, it's auto-inferred from the column's configured indexes (priority: unique > match > ore > ste_vec).

Query Result Formatting (returnType)

By default encryptQuery returns an Encrypted object (the raw EQL JSON payload). Use returnType to change the output format:

returnTypeOutputUse case
'eql' (default)Encrypted objectParameterized queries, ORMs accepting JSON
'composite-literal'stringSupabase .eq(), string-based APIs
'escaped-composite-literal'stringEmbedding inside another string or JSON value
// Get a composite literal string for use with Supabase
const term = await client.encryptQuery("alice@example.com", {
  column: users.email,
  table: users,
  queryType: "equality",
  returnType: "composite-literal",
})
// term.data is a string

Each term in a batch can have its own returnType.

Searchable JSON

For columns using .searchableJson(), the query type is auto-inferred from the plaintext:

// String -> JSONPath selector query
const pathQuery = await client.encryptQuery("$.user.email", {
  column: documents.metadata,
  table: documents,
})

// Object/Array -> containment query
const containsQuery = await client.encryptQuery({ role: "admin" }, {
  column: documents.metadata,
  table: documents,
})

Batch Query Encryption

Encrypt multiple query terms in one ZeroKMS call:

const terms = [
  { value: "alice@example.com", column: users.email, table: users, queryType: "equality" as const },
  { value: "bob", column: users.email, table: users, queryType: "freeTextSearch" as const },
]

const results = await client.encryptQuery(terms)
// results.data = [EncryptedPayload, EncryptedPayload]

All values in the array must be non-null.

Identity-Aware Encryption (Lock Contexts)

Lock encryption to a specific user by requiring a valid JWT for decryption.

import { LockContext } from "@cipherstash/stack/identity"

// 1. Create a lock context (defaults to the "sub" claim)
const lc = new LockContext()
// Or with custom claims: new LockContext({ context: { identityClaim: ["sub", "org_id"] } })
// Or with a pre-fetched CTS token: new LockContext({ ctsToken: { accessToken: "...", expiry: 123456 } })

// 2. Identify the user with their JWT
const identifyResult = await lc.identify(userJwt)
if (identifyResult.failure) {
  throw new Error(identifyResult.failure.message)
}
const lockContext = identifyResult.data

// 3. Encrypt with lock context
const encrypted = await client
  .encrypt("sensitive data", { column: users.email, table: users })
  .withLockContext(lockContext)

// 4. Decrypt with the same lock context
const decrypted = await client
  .decrypt(encrypted.data)
  .withLockContext(lockContext)

Lock contexts work with ALL operations: encrypt, decrypt, encryptModel, decryptModel, bulkEncrypt, bulkDecrypt, bulkEncryptModels, bulkDecryptModels, encryptQuery.

CTS Token Service

The lock context exchanges the JWT for a CTS (CipherStash Token Service) token. Set the endpoint:

CS_CTS_ENDPOINT=https://ap-southeast-2.aws.auth.viturhosted.net

Multi-Tenant Encryption (Keysets)

Isolate encryption keys per tenant:

// By name
const client = await Encryption({
  schemas: [users],
  config: { keyset: { name: "Company A" } },
})

// By UUID
const client = await Encryption({
  schemas: [users],
  config: { keyset: { id: "123e4567-e89b-12d3-a456-426614174000" } },
})

Each keyset provides full cryptographic isolation between tenants.

Operation Chaining

All operations return thenable objects that support chaining:

const result = await client
  .encrypt(plaintext, { column: users.email, table: users })
  .withLockContext(lockContext)         // optional: identity-aware
  .audit({ metadata: { action: "create" } }) // optional: audit trail

Error Handling

All async methods return a Result object - a discriminated union with either data (success) or failure (error), never both.

const result = await client.encrypt("hello", { column: users.email, table: users })

if (result.failure) {
  console.error(result.failure.type, result.failure.message)
  // type is one of: "ClientInitError" | "EncryptionError" | "DecryptionError"
  //                  | "LockContextError" | "CtsTokenError"
} else {
  console.log(result.data)
}

Error Types

TypeWhen
ClientInitErrorClient initialization fails (bad credentials, missing config)
EncryptionErrorAn encrypt operation fails (has optional code field)
DecryptionErrorA decrypt operation fails
LockContextErrorLock context creation or usage fails
CtsTokenErrorIdentity token exchange fails

StackError is a discriminated union of all the error types above, enabling exhaustive switch handling. EncryptionErrorTypes provides runtime constants for each error type string. Use getErrorMessage(error: unknown): string to safely extract a message from any thrown value.

import { EncryptionErrorTypes, type StackError, getErrorMessage } from "@cipherstash/stack/errors"

function handleError(error: StackError) {
  switch (error.type) {
    case EncryptionErrorTypes.ClientInitError:
      console.error("Init failed:", error.message)
      break
    case EncryptionErrorTypes.EncryptionError:
      console.error("Encrypt failed:", error.message, error.code)
      break
    case EncryptionErrorTypes.DecryptionError:
      console.error("Decrypt failed:", error.message)
      break
    case EncryptionErrorTypes.LockContextError:
      console.error("Lock context failed:", error.message)
      break
    case EncryptionErrorTypes.CtsTokenError:
      console.error("CTS token failed:", error.message)
      break
    default:
      // TypeScript ensures exhaustiveness
      const _exhaustive: never = error
  }
}

// Safe error message extraction from unknown errors
try {
  await client.encrypt("data", { column: users.email, table: users })
} catch (e) {
  console.error(getErrorMessage(e))
}

Validation Rules

  • NaN and Infinity are rejected for numeric values
  • freeTextSearch index only supports string values
  • At least one encryptedTable schema must be provided
  • Keyset UUIDs must be valid format

Ordering Encrypted Data

ORDER BY on encrypted columns requires operator family support in the database.

On databases without operator families (e.g. Supabase, or when EQL is installed with --exclude-operator-family), sorting on encrypted columns is not currently supported — regardless of the client or ORM used. This applies to Drizzle, the Supabase JS SDK, raw SQL, and any other database client.

Workaround: Sort application-side after decrypting the results.

Operator family support for Supabase is being developed in collaboration with the Supabase and CipherStash teams and will be available in a future release.

PostgreSQL Storage

Encrypted data is stored as EQL (Encrypt Query Language) JSON payloads. Install the EQL extension in PostgreSQL:

CREATE EXTENSION IF NOT EXISTS eql_v2;

CREATE TABLE users (
  id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
  email eql_v2_encrypted
);

Or store as JSONB if not using the EQL extension directly:

CREATE TABLE users (
  id SERIAL PRIMARY KEY,
  email jsonb NOT NULL
);

Migration from @cipherstash/protect

@cipherstash/protect@cipherstash/stackImport Path
protect(config)Encryption(config)@cipherstash/stack
csTable(name, cols)encryptedTable(name, cols)@cipherstash/stack/schema
csColumn(name)encryptedColumn(name)@cipherstash/stack/schema
LockContext from /identifyLockContext from /identity@cipherstash/stack/identity

All method signatures on the encryption client remain the same. The Result pattern is unchanged.

Complete API Reference

EncryptionClient Methods

MethodSignatureReturns
encrypt(plaintext, {column, table})EncryptOperation
decrypt(encryptedData)DecryptOperation
encryptQuery(plaintext, {column, table, queryType?, returnType?})EncryptQueryOperation
encryptQuery(terms: readonly ScalarQueryTerm[])BatchEncryptQueryOperation
encryptModel(model, table)EncryptModelOperation<EncryptedFromSchema<T, S>>
decryptModel(encryptedModel)DecryptModelOperation<T> — resolves to Decrypted<T>
bulkEncrypt(plaintexts, {column, table})BulkEncryptOperation
bulkDecrypt(encryptedPayloads)BulkDecryptOperation
bulkEncryptModels(models, table)BulkEncryptModelsOperation<EncryptedFromSchema<T, S>>
bulkDecryptModels(encryptedModels)BulkDecryptModelsOperation<T> — resolves to Decrypted<T>[]

All operations are thenable (awaitable) and support .withLockContext() and .audit() chaining.

Schema Builders

encryptedTable(tableName: string, columns: Record<string, EncryptedColumn | EncryptedField | nested>)
encryptedColumn(columnName: string) // chainable: .equality(), .freeTextSearch(), .orderAndRange(), .searchableJson(), .dataType()
encryptedField(valueName: string)   // for nested encrypted fields (not searchable), chainable: .dataType()

平台分布

Codex

34.19%
按下载量换算31

Claude

31.5%
按下载量换算29

Cursor

21.29%
按下载量换算20

Gemini CLI

9.1%
按下载量换算8

安全审计

Gen Agent Trust Hub

通过

Socket

通过

Snyk

通过

权限和风险

接触敏感数据

该 Skill 可能接触密钥、Token、环境变量或敏感配置,应进入高风险复核队列,默认不自动发布。

安装前确认

本站仅展示第三方公开信息,不托管安装包,不提供自动安装或运行环境。安装前应自行审查源码、依赖和命令行为。目前只有一个公开来源,建议同时核对源仓库。

继续浏览同类 Skills