Skip to content
KitploitKITPLOIT
ToolsBlog
Submit
ToolsBlog
Submit

Hacking, PenTest, and Cybersecurity Tools for Your Security Arsenal!

Kitploit is a directory of hacking, cybersecurity, and pentesting tools. Discover the latest project updates to find vulnerabilities, analyze systems, automate testing, and strengthen your security.

··Feeds·Contact·Privacy·© 2026 Kitploit

Tool Directory

Categories

View all categories
Loading categories
sdk — Thin TypeScript + zero-dep Python client and recipes to gate high-risk actions behind a payload-bound passkey approval. | Kitploit
Tools/GitLabGitLab/cosignet/sdk
Authentication & AuthorizationDevSecOpsAuthenticationLearning & EducationRed TeamingAPI Security
GitLabcosignet/sdk

sdk

Thin TypeScript + zero-dep Python client and recipes to gate high-risk actions behind a payload-bound passkey approval.

View Repository
531 month agoNot yet reviewed

Most Popular

View all →

Discover the most used tools by our community.

Explore all tools

Browse our collection of tools

View all tools →
Share

@cosignet/sdk

License: MIT TypeScript Zero dependencies Cosignet

Thin, zero-dependency TypeScript client for Cosignet — human-in-the-loop approval for high-risk AI-agent actions, with payload-bound passkey signatures.

Put a human in the loop before a dangerous action runs: pause it, get an explicit passkey approval from a person (Face ID / Touch ID / Windows Hello / security key), and continue only on a signed decision bound to the exact payload — change the action afterward and the signature no longer matches. Cosignet is an approval and evidence layer, not an executor or policy engine. Runs anywhere with global fetch + Web Crypto: Node 18+, Cloudflare Workers, Deno, and browsers.

Status: early access. Published on npm as @cosignet/sdk.

Install

root@kitploit:~
npm install @cosignet/sdk

Request an approval and wait for the decision

root@kitploit:~
import { Cosignet } from '@cosignet/sdk';

const cosignet = new Cosignet({ apiKey: process.env.COSIGNET_API_KEY! });

const decision = await cosignet.requestApproval(
  {
    username: 'alex',
    action: 'Wire transfer to vendor',
    payload: { to: 'acct_8821', amount_usd: 4200, memo: 'INV-2025-118' },
    notify: 'telegram_or_email',
  },
  { onCreated: (c) => console.log('Approve here:', c.url) },
);

if (decision.status === 'approved') {
  // proceed — decision.rawAssertion is the signed proof
} else {
  // 'rejected' | 'expired' | 'pending' (timed out)
}

requestApproval long-polls over your own outbound connection (~25s hops), so it works from CLI tools and locked-down VPCs behind NAT/firewalls — no inbound webhook, open port, or public IP required.

Fail closed when Cosignet is unavailable

If your system cannot obtain a signed approval, the gated action must not run. Unavailability must never degrade into auto-approval. Treat every timeout, network error, and 5xx as "not approved".

Implementation notes:

  • Distinguish "rejected" from "unavailable" in your logs and alerts. One is a human decision, the other is an operational condition.
  • Retry reads with exponential backoff and jitter; cap total wait at your action's own deadline, then treat as expired.
  • Make gated actions idempotent on your side, so a retry after an unclear state cannot double-execute.
  • Never cache an approval for reuse. A signed decision is bound to one payload hash; treat it as single-use.

See When Cosignet is unavailable for the full availability and break-glass guidance.

Lower-level calls

root@kitploit:~
const created = await cosignet.createConfirmation({ username, action, payload });
const status  = await cosignet.getConfirmation(created.id, { wait: 25 }); // long-poll

Safe retries with an idempotency key

Pass idempotencyKey (sent as the Idempotency-Key header) so a retried create — e.g. after a network blip interrupts a long-poll — with the same key and same action/payload returns the original confirmation (idempotent: true) instead of minting a duplicate or re-notifying the approver. Reusing a key with different parameters is rejected with a 422.

root@kitploit:~
await cosignet.createConfirmation({
  username: 'alex',
  action: 'Wire transfer to vendor',
  payload: { to: 'acct_8821', amount_usd: 4200 },
  idempotencyKey: 'wire-INV-2025-118', // stable per logical operation
});

Send the approver back to your app

Pass returnUrl to show a "Return to <host>" button on the approval page once the request resolves (approved / rejected / expired) — handy so a human can get back to your app to re-trigger an action that timed out. It must be an https URL and is only ever rendered as a click-through link (never fetched server-side).

root@kitploit:~
await cosignet.requestApproval({
  username: 'alex',
  action: 'Wire transfer to vendor',
  payload: { to: 'acct_8821', amount_usd: 4200 },
  returnUrl: 'https://app.example.com/approvals',
});

Notifications

notify ('none' | 'telegram' | 'email' | 'telegram_or_email') controls the personal-reach ping to the specific signer:

  • telegram — a DM to the approver's linked Telegram (telegram_or_email prefers this when the approver has linked a chat).
  • email — an email to the approver's own address. Priority: the direct email you set on the approver in the dashboard (delivery-only), then their verified member email, then the account contact address as a last resort.
  • telegram_or_email — Telegram if linked, otherwise the email above.
  • none — no personal ping.

Separately, team reach is a Slack broadcast to a shared channel, configured per-account in the dashboard. It is additive and always fires when configured, independent of notify (so notify:'none' still posts to Slack). Approvers get their Telegram and email set from the dashboard's Approvers section.

Note on public: true reveal: the email committed into the transparency log is the account's designated verified email (chosen in dashboard settings, as the accountable party — not the individual signer). The direct notify email is delivery-only and never used for the reveal hash.

Every channel is link-only: the notification carries the approval URL and never the action or payload. Approval always requires the approver's payload-bound passkey on the confirmation page — there is no approve-in-channel.

Verify a webhook

verifyWebhookSignature recomputes the hex HMAC-SHA256 of the raw request body and constant-time compares it to the Cosignet-Signature header. Pass the exact bytes you received — re-serializing JSON changes the signature.

root@kitploit:~
import { verifyWebhookSignature } from '@cosignet/sdk';

const ok = await verifyWebhookSignature({
  body: rawBody,                              // raw string, not re-parsed JSON
  signature: req.headers['cosignet-signature'],
  secret: process.env.COSIGNET_WEBHOOK_SECRET!,
  timestamp: req.headers['cosignet-timestamp'], // optional replay protection
  toleranceSeconds: 300,                         // optional
});
if (!ok) return res.status(401).end();

Verification

See docs/verification.md for the caller-side checklist: continue only on approved, compare the decision to the operation you are about to run, and treat rejected/expired/timeouts as hard stops.

API

  • new Cosignet({ apiKey, baseUrl?, fetch? })
  • createConfirmation(input) → CreatedConfirmation
  • getConfirmation(id, { wait? }) → Confirmation
  • requestApproval(input, { timeoutMs?, onCreated? }) → Confirmation
  • verifyWebhookSignature({ body, signature, secret, timestamp?, toleranceSeconds? }) → Promise<boolean>

Public approval reveal (opt-in, off by default)

By default the transparency log withholds the payload and exposes no approver identity. Set public: true on createConfirmation/requestApproval to opt a single approval into public reveal: its raw action + payload become readable in the verification bundle, and a PBKDF2 hash of the account's designated verified email (chosen in dashboard settings — the accountable party, not the individual signer) is committed into the Merkle leaf so anyone can check a candidate address against it.

root@kitploit:~
await cosignet.requestApproval({
  username: 'alice',
  action: 'Publish Q3 board resolution',
  payload: { docId: 'res-2026-Q3' },
  public: true, // permanent, irreversible — see caveats below
});
  • Permanent and irreversible — once published it cannot be unpublished.
  • Requires public reveal to be enabled for your account (dashboard settings); otherwise the request is rejected.
  • Honesty: the payload reveal is passkey-bound (strong); the email hash is attested by Cosignet's signed tree head — not signed by the passkey — and email is low-entropy, so a match proves a known address rather than anonymity. The committed email names the account's chosen accountable party, not necessarily the individual who signed; when no email is chosen the leaf reveals payload only.
  • Don't enable it for confirmations containing secrets or personal data.

Examples & security docs

  • examples/ — copy-pasteable cURL, Node, Python, GitLab CI, MCP/tool-wrapper, and Worker examples.
  • security/ — payload binding, WebAuthn proof model, threat model, transparency log, and responsible disclosure.

Recipes

Gate high-risk actions behind a passkey approval:

  • recipes/ai-agent-gate — pause an AI coding agent (Claude Code) before it runs a dangerous shell command until a human co-signs.
  • recipes/cli-approval — wrap any command (e.g. terraform destroy).
  • recipes/ci-cd — block a pipeline (GitHub Actions / GitLab CI) on approval.
  • recipes/backend-service — pause an irreversible op in a service.

Feedback and requests

  • Feature requests, product ideas, SDK/API ergonomics, and roadmap discussion: open a Feature issue.
  • Requests for new examples or integrations: open an Example request issue.
  • Security reports: email [email protected]; do not file public issues for vulnerabilities.

Contributing & security

  • Code, issues, and discussion live on GitLab: https://gitlab.com/cosignet/sdk.
  • Contributions welcome — see CONTRIBUTING and our Code of Conduct.
  • Report vulnerabilities privately: SECURITY.md · [email protected].

License

MIT © Cosignet

Download Tool
SignalMeaningYour action
status: approved (signature verifies)Human approved this exact payloadProceed
status: rejectedHuman rejectedDo not run; surface to requester
status: expiredNobody decided in timeDo not run; re-request if still needed
Timeout, network error, or 5xxUnknown stateDo not run; retry with backoff; alert after N failures