auramaxx 1.0.0-alpha.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (363) hide show
  1. package/LICENSE +26 -0
  2. package/README.md +112 -0
  3. package/bin/aurawallet.js +121 -0
  4. package/docs/ADAPTERS.md +467 -0
  5. package/docs/API.md +2679 -0
  6. package/docs/APPS.md +198 -0
  7. package/docs/ARCHITECTURE.md +350 -0
  8. package/docs/AUTH.md +698 -0
  9. package/docs/BEST-PRACTICES.md +121 -0
  10. package/docs/CLI.md +61 -0
  11. package/docs/DEVELOPING-APPS.md +452 -0
  12. package/docs/EXTENSION.md +97 -0
  13. package/docs/JOBS.md +33 -0
  14. package/docs/MCP.md +76 -0
  15. package/docs/PROTOCOL.md +142 -0
  16. package/docs/SETUP.md +219 -0
  17. package/docs/WORKSPACE.md +672 -0
  18. package/docs/agent-auth.md +63 -0
  19. package/docs/aura-file.md +48 -0
  20. package/docs/credentials.md +53 -0
  21. package/docs/external/getting-started.md +65 -0
  22. package/docs/external/overview.md +45 -0
  23. package/docs/external/use-cases.md +48 -0
  24. package/docs/external/why-aura.md +35 -0
  25. package/docs/jobs/connect-agent.md +77 -0
  26. package/docs/jobs/migrate-from-dotenv.md +79 -0
  27. package/docs/jobs/recover-from-lockout.md +72 -0
  28. package/docs/jobs/secure-ci.md +63 -0
  29. package/docs/oauth2.md +42 -0
  30. package/docs/passkeys.md +60 -0
  31. package/docs/security.md +540 -0
  32. package/docs/specs/aura-open-protocol.md +61 -0
  33. package/docs/specs/aura-provider-plugin.md +24 -0
  34. package/docs/specs/aura-registry-model.md +31 -0
  35. package/docs/specs/fixtures/invalid-bad-key.aura +1 -0
  36. package/docs/specs/fixtures/invalid-bad-unicode-escape.aura +1 -0
  37. package/docs/specs/fixtures/invalid-duplicate-key.aura +2 -0
  38. package/docs/specs/fixtures/valid-basic.aura +4 -0
  39. package/docs/specs/fixtures/valid-provider-ref.aura +1 -0
  40. package/docs/specs/fixtures/valid-quoted-escapes.aura +2 -0
  41. package/docs/templates/RELEASE_NOTES_TEMPLATE.md +22 -0
  42. package/docs/totp.md +40 -0
  43. package/docs/wallet/AI.md +508 -0
  44. package/docs/wallet/DEVELOPING-STRATEGIES.md +713 -0
  45. package/docs/wallet/README.md +47 -0
  46. package/docs/wallet/STRATEGY.md +89 -0
  47. package/next.config.ts +21 -0
  48. package/package.json +151 -0
  49. package/postcss.config.mjs +8 -0
  50. package/prisma/migrations/20260214170000_baseline/migration.sql +511 -0
  51. package/prisma/migrations/20260216214537_add_passkey_model/migration.sql +18 -0
  52. package/prisma/migrations/20260217150500_add_credential_access_audit/migration.sql +31 -0
  53. package/prisma/migrations/migration_lock.toml +3 -0
  54. package/prisma/schema.prisma +447 -0
  55. package/public/logo-chevron.svg +31 -0
  56. package/public/logo-concentric.svg +31 -0
  57. package/public/logo-crosshatch.svg +39 -0
  58. package/public/logo-dashed.svg +39 -0
  59. package/public/logo-horizontal.svg +31 -0
  60. package/public/logo-m56.svg +64 -0
  61. package/public/logo.webp +0 -0
  62. package/scripts/add-app.js +245 -0
  63. package/scripts/init.sh +57 -0
  64. package/scripts/migrate-apikeys-to-credentials.ts +35 -0
  65. package/scripts/sandbox-agent-flow.sh +235 -0
  66. package/scripts/sandbox.sh +175 -0
  67. package/scripts/validate-job-docs.mjs +125 -0
  68. package/server/abi/SwapHelper.json +438 -0
  69. package/server/cli/approval.ts +447 -0
  70. package/server/cli/commands/app.ts +204 -0
  71. package/server/cli/commands/cron.ts +24 -0
  72. package/server/cli/commands/doctor.ts +1007 -0
  73. package/server/cli/commands/env.ts +456 -0
  74. package/server/cli/commands/init.ts +752 -0
  75. package/server/cli/commands/mcp.ts +125 -0
  76. package/server/cli/commands/restore.ts +314 -0
  77. package/server/cli/commands/shell-hook.ts +468 -0
  78. package/server/cli/commands/start.ts +62 -0
  79. package/server/cli/commands/status.ts +59 -0
  80. package/server/cli/commands/stop.ts +14 -0
  81. package/server/cli/commands/token.ts +180 -0
  82. package/server/cli/commands/unlock.ts +49 -0
  83. package/server/cli/commands/vault.ts +417 -0
  84. package/server/cli/index.ts +328 -0
  85. package/server/cli/lib/aura-parser.ts +64 -0
  86. package/server/cli/lib/credential-create.ts +74 -0
  87. package/server/cli/lib/credential-resolve.ts +254 -0
  88. package/server/cli/lib/dotenv-migrate.ts +116 -0
  89. package/server/cli/lib/dotenv-parser.ts +146 -0
  90. package/server/cli/lib/http.ts +91 -0
  91. package/server/cli/lib/init-steps.ts +76 -0
  92. package/server/cli/lib/local-agent-trust.ts +45 -0
  93. package/server/cli/lib/process.ts +136 -0
  94. package/server/cli/lib/prompt.ts +85 -0
  95. package/server/cli/lib/theme.ts +240 -0
  96. package/server/cli/socket.ts +570 -0
  97. package/server/cli/transport-client.ts +50 -0
  98. package/server/cron/index.ts +137 -0
  99. package/server/cron/job.ts +31 -0
  100. package/server/cron/jobs/balance-sync.ts +436 -0
  101. package/server/cron/jobs/incoming-scan.ts +506 -0
  102. package/server/cron/jobs/native-price.ts +70 -0
  103. package/server/cron/jobs/orphan-cleanup.ts +40 -0
  104. package/server/cron/jobs/strategy-runner.ts +175 -0
  105. package/server/cron/scheduler.ts +125 -0
  106. package/server/index.ts +406 -0
  107. package/server/lib/adapters/factory.ts +110 -0
  108. package/server/lib/adapters/index.ts +19 -0
  109. package/server/lib/adapters/router.ts +297 -0
  110. package/server/lib/adapters/telegram.ts +645 -0
  111. package/server/lib/adapters/types.ts +89 -0
  112. package/server/lib/adapters/webhook.ts +95 -0
  113. package/server/lib/address.ts +49 -0
  114. package/server/lib/agent-auth/contracts.ts +1194 -0
  115. package/server/lib/agent-profiles.ts +328 -0
  116. package/server/lib/ai.ts +285 -0
  117. package/server/lib/api-registry/contracts.ts +86 -0
  118. package/server/lib/api-registry/validation.ts +172 -0
  119. package/server/lib/apikey-migration.ts +189 -0
  120. package/server/lib/app-installer.ts +505 -0
  121. package/server/lib/app-tokens.ts +247 -0
  122. package/server/lib/auth.ts +314 -0
  123. package/server/lib/batch.ts +242 -0
  124. package/server/lib/cold.ts +874 -0
  125. package/server/lib/config.ts +381 -0
  126. package/server/lib/credential-access-audit.ts +85 -0
  127. package/server/lib/credential-access-policy.ts +110 -0
  128. package/server/lib/credential-health.ts +343 -0
  129. package/server/lib/credential-import.ts +487 -0
  130. package/server/lib/credential-scope.ts +87 -0
  131. package/server/lib/credential-shares.ts +190 -0
  132. package/server/lib/credential-transport.ts +342 -0
  133. package/server/lib/credential-vault.ts +77 -0
  134. package/server/lib/credentials.ts +333 -0
  135. package/server/lib/crypto.ts +8 -0
  136. package/server/lib/db.ts +15 -0
  137. package/server/lib/defaults.ts +366 -0
  138. package/server/lib/dex/index.ts +80 -0
  139. package/server/lib/dex/relay.ts +235 -0
  140. package/server/lib/dex/types.ts +59 -0
  141. package/server/lib/dex/uniswap.ts +370 -0
  142. package/server/lib/e2e-agent/artifacts.ts +36 -0
  143. package/server/lib/e2e-agent/contracts.ts +112 -0
  144. package/server/lib/e2e-agent/validation.ts +135 -0
  145. package/server/lib/encrypt.ts +128 -0
  146. package/server/lib/error.ts +20 -0
  147. package/server/lib/events.ts +205 -0
  148. package/server/lib/hot.ts +357 -0
  149. package/server/lib/key-fingerprint.ts +28 -0
  150. package/server/lib/logger.ts +331 -0
  151. package/server/lib/network.ts +137 -0
  152. package/server/lib/notifications.ts +219 -0
  153. package/server/lib/oauth2-refresh.ts +241 -0
  154. package/server/lib/oursecret.ts +54 -0
  155. package/server/lib/passkey-credential.ts +360 -0
  156. package/server/lib/passkey.ts +68 -0
  157. package/server/lib/permissions.ts +248 -0
  158. package/server/lib/pino.ts +24 -0
  159. package/server/lib/policy-preview.ts +138 -0
  160. package/server/lib/price.ts +338 -0
  161. package/server/lib/prices.ts +34 -0
  162. package/server/lib/project-scope.ts +239 -0
  163. package/server/lib/resolve-action.ts +427 -0
  164. package/server/lib/resolve.ts +36 -0
  165. package/server/lib/sessions.ts +632 -0
  166. package/server/lib/solana/connection.ts +26 -0
  167. package/server/lib/solana/jupiter.ts +128 -0
  168. package/server/lib/solana/transfer.ts +108 -0
  169. package/server/lib/solana/wallet.ts +136 -0
  170. package/server/lib/strategy/emits.ts +21 -0
  171. package/server/lib/strategy/engine.ts +1305 -0
  172. package/server/lib/strategy/executor.ts +115 -0
  173. package/server/lib/strategy/hook-context.ts +158 -0
  174. package/server/lib/strategy/hooks.ts +990 -0
  175. package/server/lib/strategy/index.ts +28 -0
  176. package/server/lib/strategy/installer.ts +305 -0
  177. package/server/lib/strategy/loader.ts +256 -0
  178. package/server/lib/strategy/message.ts +235 -0
  179. package/server/lib/strategy/repository.ts +218 -0
  180. package/server/lib/strategy/session-logger.ts +693 -0
  181. package/server/lib/strategy/sources.ts +288 -0
  182. package/server/lib/strategy/state.ts +189 -0
  183. package/server/lib/strategy/templates.ts +403 -0
  184. package/server/lib/strategy/tick.ts +404 -0
  185. package/server/lib/strategy/types.ts +230 -0
  186. package/server/lib/swap.ts +3 -0
  187. package/server/lib/temp.ts +86 -0
  188. package/server/lib/token-metadata.ts +86 -0
  189. package/server/lib/token-safety.ts +200 -0
  190. package/server/lib/token-search.ts +444 -0
  191. package/server/lib/totp.ts +194 -0
  192. package/server/lib/transactions.ts +123 -0
  193. package/server/lib/transport.ts +75 -0
  194. package/server/lib/txhistory/decoder.ts +262 -0
  195. package/server/lib/txhistory/enricher.ts +652 -0
  196. package/server/lib/txhistory/index.ts +391 -0
  197. package/server/lib/txhistory/signatures.ts +59 -0
  198. package/server/lib/verified-summary.ts +421 -0
  199. package/server/mcp/profile-policy.ts +30 -0
  200. package/server/mcp/server.ts +619 -0
  201. package/server/mcp/tools.ts +523 -0
  202. package/server/middleware/auth.ts +119 -0
  203. package/server/middleware/requestLogger.ts +84 -0
  204. package/server/routes/actions.ts +459 -0
  205. package/server/routes/adapters.ts +703 -0
  206. package/server/routes/addressbook.ts +113 -0
  207. package/server/routes/ai.ts +34 -0
  208. package/server/routes/apikeys.ts +295 -0
  209. package/server/routes/apps.ts +601 -0
  210. package/server/routes/auth.ts +457 -0
  211. package/server/routes/backup.ts +340 -0
  212. package/server/routes/batch.ts +270 -0
  213. package/server/routes/bookmarks.ts +162 -0
  214. package/server/routes/credential-shares.ts +198 -0
  215. package/server/routes/credential-vaults.ts +154 -0
  216. package/server/routes/credentials.ts +1290 -0
  217. package/server/routes/dashboard.ts +71 -0
  218. package/server/routes/defaults.ts +124 -0
  219. package/server/routes/fund.ts +229 -0
  220. package/server/routes/import.ts +352 -0
  221. package/server/routes/launch.ts +665 -0
  222. package/server/routes/lock.ts +54 -0
  223. package/server/routes/logs.ts +68 -0
  224. package/server/routes/nuke.ts +111 -0
  225. package/server/routes/passkey-credentials.ts +99 -0
  226. package/server/routes/passkey.ts +346 -0
  227. package/server/routes/portfolio.ts +217 -0
  228. package/server/routes/price.ts +63 -0
  229. package/server/routes/resolve.ts +31 -0
  230. package/server/routes/security.ts +45 -0
  231. package/server/routes/send-evm.ts +241 -0
  232. package/server/routes/send-solana.ts +281 -0
  233. package/server/routes/send.ts +178 -0
  234. package/server/routes/setup.ts +210 -0
  235. package/server/routes/strategy.ts +894 -0
  236. package/server/routes/swap-evm.ts +353 -0
  237. package/server/routes/swap-solana.ts +177 -0
  238. package/server/routes/swap.ts +356 -0
  239. package/server/routes/token.ts +247 -0
  240. package/server/routes/unlock.ts +403 -0
  241. package/server/routes/wallet-assets.ts +361 -0
  242. package/server/routes/wallet-transactions.ts +515 -0
  243. package/server/routes/wallet.ts +710 -0
  244. package/server/types.ts +146 -0
  245. package/skills/aurawallet/SKILL.md +739 -0
  246. package/skills/aurawallet-setup/SKILL.md +74 -0
  247. package/skills/security-review/SKILL.md +148 -0
  248. package/src/app/api/agent-requests/route.ts +30 -0
  249. package/src/app/api/apps/install/route.ts +126 -0
  250. package/src/app/api/apps/manifests/route.ts +16 -0
  251. package/src/app/api/apps/static/[...path]/route.ts +57 -0
  252. package/src/app/api/events/route.ts +92 -0
  253. package/src/app/api/page.tsx +212 -0
  254. package/src/app/api/workspace/[id]/apps/[wid]/route.ts +119 -0
  255. package/src/app/api/workspace/[id]/apps/route.ts +81 -0
  256. package/src/app/api/workspace/[id]/export/route.ts +67 -0
  257. package/src/app/api/workspace/[id]/route.ts +168 -0
  258. package/src/app/api/workspace/auth.ts +34 -0
  259. package/src/app/api/workspace/config/route.ts +106 -0
  260. package/src/app/api/workspace/import/route.ts +127 -0
  261. package/src/app/api/workspace/route.ts +116 -0
  262. package/src/app/app/page.tsx +2122 -0
  263. package/src/app/apple-icon.png +0 -0
  264. package/src/app/docs/page.tsx +178 -0
  265. package/src/app/favicon.ico +0 -0
  266. package/src/app/globals.css +572 -0
  267. package/src/app/health/page.tsx +5 -0
  268. package/src/app/hello/page.tsx +15 -0
  269. package/src/app/icon.png +0 -0
  270. package/src/app/layout.tsx +34 -0
  271. package/src/app/page.tsx +986 -0
  272. package/src/app/providers.tsx +90 -0
  273. package/src/app/share/[token]/page.tsx +295 -0
  274. package/src/components/ChainSelector.tsx +144 -0
  275. package/src/components/HumanActionBar.tsx +695 -0
  276. package/src/components/NotificationDrawer.tsx +129 -0
  277. package/src/components/apps/AgentKeysApp.tsx +490 -0
  278. package/src/components/apps/App.tsx +153 -0
  279. package/src/components/apps/AppGrid.tsx +15 -0
  280. package/src/components/apps/DetailedAddressDrawer.tsx +325 -0
  281. package/src/components/apps/DraggableApp.tsx +562 -0
  282. package/src/components/apps/IFrameApp.tsx +73 -0
  283. package/src/components/apps/LogsApp.tsx +360 -0
  284. package/src/components/apps/SendApp.tsx +394 -0
  285. package/src/components/apps/SetupWizardApp.tsx +1004 -0
  286. package/src/components/apps/SystemDefaultsApp.tsx +845 -0
  287. package/src/components/apps/ThirdPartyApp.tsx +428 -0
  288. package/src/components/apps/TokenApp.tsx +319 -0
  289. package/src/components/apps/TransactionsApp.tsx +438 -0
  290. package/src/components/apps/WalletDetailApp.tsx +1505 -0
  291. package/src/components/apps/index.ts +13 -0
  292. package/src/components/design-system/Button.tsx +53 -0
  293. package/src/components/design-system/ChainIndicator.tsx +65 -0
  294. package/src/components/design-system/ChainSelector.tsx +137 -0
  295. package/src/components/design-system/ConfirmationModal.tsx +106 -0
  296. package/src/components/design-system/ConfirmationPopover.tsx +81 -0
  297. package/src/components/design-system/Drawer.tsx +123 -0
  298. package/src/components/design-system/FilterDropdown.tsx +72 -0
  299. package/src/components/design-system/Modal.tsx +206 -0
  300. package/src/components/design-system/Popover.tsx +142 -0
  301. package/src/components/design-system/TextInput.tsx +85 -0
  302. package/src/components/design-system/Toggle.tsx +58 -0
  303. package/src/components/design-system/index.ts +11 -0
  304. package/src/components/docs/DocsThemeToggle.tsx +49 -0
  305. package/src/components/health/CredentialHealthDashboard.tsx +214 -0
  306. package/src/components/icons/ChainIcons.tsx +72 -0
  307. package/src/components/layout/AppStoreDrawer.tsx +369 -0
  308. package/src/components/layout/ContentArea.tsx +21 -0
  309. package/src/components/layout/TabBar.tsx +278 -0
  310. package/src/components/layout/WalletSidebar.tsx +1033 -0
  311. package/src/components/layout/index.ts +4 -0
  312. package/src/components/marketing/AuraWalletSpecOverlay.tsx +635 -0
  313. package/src/components/marketing/DeviceMorphExperience.tsx +216 -0
  314. package/src/components/vault/ApiKeysConsole.tsx +1080 -0
  315. package/src/components/vault/AuditConsole.tsx +584 -0
  316. package/src/components/vault/CredentialDetail.tsx +455 -0
  317. package/src/components/vault/CredentialEmpty.tsx +55 -0
  318. package/src/components/vault/CredentialField.tsx +361 -0
  319. package/src/components/vault/CredentialForm.tsx +1212 -0
  320. package/src/components/vault/CredentialList.tsx +165 -0
  321. package/src/components/vault/CredentialRow.tsx +97 -0
  322. package/src/components/vault/CredentialShareModal.tsx +178 -0
  323. package/src/components/vault/CredentialVault.tsx +754 -0
  324. package/src/components/vault/CredentialWalletWidget.tsx +103 -0
  325. package/src/components/vault/ImportCredentialsModal.tsx +515 -0
  326. package/src/components/vault/LargeTypeModal.tsx +64 -0
  327. package/src/components/vault/PasswordGenerator.tsx +224 -0
  328. package/src/components/vault/TOTPDisplay.tsx +123 -0
  329. package/src/components/vault/VaultSidebar.tsx +413 -0
  330. package/src/components/vault/types.ts +54 -0
  331. package/src/context/AuthContext.tsx +337 -0
  332. package/src/context/PriceContext.tsx +113 -0
  333. package/src/context/ThemeContext.tsx +164 -0
  334. package/src/context/WebSocketContext.tsx +269 -0
  335. package/src/context/WorkspaceContext.tsx +668 -0
  336. package/src/hooks/index.ts +3 -0
  337. package/src/hooks/useAgentActions.ts +368 -0
  338. package/src/hooks/useBalance.ts +103 -0
  339. package/src/hooks/useBalances.ts +129 -0
  340. package/src/instrumentation.ts +12 -0
  341. package/src/lib/api.ts +449 -0
  342. package/src/lib/app-loader.ts +148 -0
  343. package/src/lib/app-registry.ts +178 -0
  344. package/src/lib/app-sdk.ts +157 -0
  345. package/src/lib/audit-console-adapter.ts +151 -0
  346. package/src/lib/auth-client.ts +75 -0
  347. package/src/lib/config.ts +74 -0
  348. package/src/lib/crypto.ts +112 -0
  349. package/src/lib/db.ts +21 -0
  350. package/src/lib/docs.ts +390 -0
  351. package/src/lib/events.ts +361 -0
  352. package/src/lib/pino.ts +24 -0
  353. package/src/lib/theme-handlers.ts +168 -0
  354. package/src/lib/theme.ts +351 -0
  355. package/src/lib/tokenData.ts +378 -0
  356. package/src/lib/vault-crypto.ts +129 -0
  357. package/src/lib/websocket-server.ts +302 -0
  358. package/src/lib/websocket-setup.ts +79 -0
  359. package/src/lib/wordlist.ts +2050 -0
  360. package/src/lib/workspace-handlers.ts +285 -0
  361. package/start.sh +80 -0
  362. package/tailwind.config.ts +99 -0
  363. package/tsconfig.json +42 -0
@@ -0,0 +1,60 @@
1
+ # Passkeys
2
+
3
+ Aura supports **two separate passkey systems**:
4
+
5
+ 1. **Vault-unlock passkeys** (`/auth/passkey/*`) for session token issuance (Face ID / Touch ID / platform authenticator).
6
+ 2. **Credential passkeys** (`/credentials/passkey/*`) for website WebAuthn registration/authentication stored in Aura credentials.
7
+
8
+ Do not treat these as the same trust boundary.
9
+
10
+ ## 1) Vault-unlock passkeys (session auth)
11
+
12
+ ### Endpoints
13
+
14
+ - `GET /auth/passkey/status`
15
+ - `POST /auth/passkey/register/options` (admin required)
16
+ - `POST /auth/passkey/register/verify` (admin required)
17
+ - `POST /auth/passkey/authenticate/options`
18
+ - `POST /auth/passkey/authenticate/verify`
19
+ - `DELETE /auth/passkey/:credentialId` (admin required)
20
+
21
+ ### Behavior
22
+
23
+ - Registration requires unlocked vault + admin token.
24
+ - Authentication verify requires caller `pubkey`; successful auth issues an admin token.
25
+ - If vault is locked after restart, passkey auth endpoints return `vault_locked` until server unlock state is restored.
26
+
27
+ ### Storage
28
+
29
+ Vault-unlock passkey records use Prisma `Passkey` model:
30
+
31
+ - `credentialId`
32
+ - `publicKey`
33
+ - `counter`
34
+ - `transports`
35
+ - `rpId`
36
+ - `aaguid`
37
+
38
+ No private key material is stored by Aura for vault-unlock authenticators.
39
+
40
+ ## 2) Credential passkeys (site passkeys)
41
+
42
+ ### Endpoints
43
+
44
+ - `GET /credentials/passkey/match?rpId=<rpId>`
45
+ - `POST /credentials/passkey/register`
46
+ - `POST /credentials/passkey/authenticate`
47
+
48
+ ### Behavior
49
+
50
+ - Extension intercepts `navigator.credentials.create()` / `get()` and routes through Aura.
51
+ - Registration requires explicit user confirmation in extension UI.
52
+ - Authentication:
53
+ - Honors RP `allowCredentials` ordering when provided.
54
+ - Shows picker UI when multiple Aura passkeys match.
55
+ - Requires explicit confirmation for single-match authentication.
56
+ - If Aura has no match, user denies, server is unavailable, or the request times out, flow declines so browser can fall back to native WebAuthn handling.
57
+
58
+ ### Storage
59
+
60
+ Credential passkeys are stored as first-class `passkey` credentials in Aura credential storage with encrypted private key material and metadata (e.g. `rpId`, `credentialId`, `publicKey`, `userHandle`, `signCount`, transports/discoverable flags).
@@ -0,0 +1,540 @@
1
+ # Security Architecture
2
+
3
+ This document describes the security model and architecture for AuraWallet.
4
+
5
+ ## Core Principles
6
+
7
+ 1. **Memory-only authentication** - All auth decisions use in-memory state only
8
+ 2. **Restart invalidates all tokens** - New SIGNING_KEY on restart = forced re-approval
9
+ 3. **Minimal permissions** - Agents request only what they need
10
+ 4. **Human controls cold wallet** - All cold wallet operations require human approval
11
+ 5. **Wallet ownership** - Agents can only access wallets they created
12
+
13
+ ---
14
+
15
+ ## Threat Model
16
+
17
+ ### Adversary Personas
18
+
19
+ | Persona | Description | Access Level |
20
+ |---------|-------------|--------------|
21
+ | **Rogue Agent** | Compromised or malicious AI agent with a valid token | Network access to localhost:4242, limited permissions |
22
+ | **Local Malware** | Malware running on the same machine as the server | File system access, process inspection, network sniffing |
23
+ | **Database Attacker** | Attacker who obtains a copy of the SQLite database | Read access to `~/.aurawallet/aurawallet.db` |
24
+ | **Network Observer** | Process or tool intercepting localhost HTTP traffic | Can read/modify HTTP requests between agent and server |
25
+
26
+ ### Asset Values
27
+
28
+ | Asset | Storage | Compromise Impact |
29
+ |-------|---------|-------------------|
30
+ | **Cold mnemonic** | Encrypted file (AES-256-GCM, password-derived key) → decrypted in memory only when unlocked | Total fund loss — full control of cold wallet and all derived addresses |
31
+ | **Hot wallet private keys** | DB (AES-256-GCM, encrypted with cold mnemonic) | Loss of individual hot wallet funds |
32
+ | **SIGNING_KEY** | Memory only (random 32 bytes) | Token forgery — can create tokens with any permissions |
33
+ | **Agent tokens** | Memory only (HMAC-signed payloads) | Impersonation — spend within token's limits/permissions |
34
+ | **Vault password** | Never stored (used to decrypt vault file) | Can unlock vault → access cold mnemonic |
35
+
36
+ ### Risk Matrix
37
+
38
+ | Attack | Likelihood | Impact | Mitigation |
39
+ |--------|-----------|--------|------------|
40
+ | Agent exceeds intended scope | Medium | Medium | Permission system, spending limits, wallet ownership |
41
+ | Localhost traffic interception | Low | High | RSA-OAEP password encryption, tokens are bearer-only |
42
+ | Database file exfiltration | Low | Low | DB alone cannot forge auth or decrypt cold wallet |
43
+ | Memory dump of server process | Very Low | Critical | OS-level protection; restart invalidates all state |
44
+ | Brute-force vault password | Low | Critical | Rate limit: 5 attempts / 15 min on unlock endpoints |
45
+
46
+ ---
47
+
48
+ ## Architecture Overview
49
+
50
+ ```
51
+ ┌──────────────────────────────────────────────────────────────────┐
52
+ │ MEMORY (Security-Critical) │
53
+ ├──────────────────────────────────────────────────────────────────┤
54
+ │ SIGNING_KEY - Random 32 bytes, regenerates on restart │
55
+ │ sessions Map - tokenHash → { token, spentByType } │
56
+ │ revokedTokens Set - Revoked token hashes │
57
+ │ vaultSessions Map - vaultId → { mnemonic, address, ... } │
58
+ │ (per-vault unlock state, replaces │
59
+ │ singleton unlockedMnemonic) │
60
+ └──────────────────────────────────────────────────────────────────┘
61
+
62
+
63
+ ┌──────────────────────────────────────────────────────────────────┐
64
+ │ DATABASE (Display Only) │
65
+ ├──────────────────────────────────────────────────────────────────┤
66
+ │ AgentToken - For UI display, NOT for auth decisions │
67
+ │ HotWallet - Encrypted private keys + ownership │
68
+ │ HumanAction - Pending actions awaiting human approval │
69
+ │ ApiKey - Stored API keys │
70
+ │ Log - Audit trail │
71
+ └──────────────────────────────────────────────────────────────────┘
72
+ ```
73
+
74
+ **Key insight**: A stolen database is useless without the in-memory SIGNING_KEY.
75
+
76
+ ---
77
+
78
+ ## Token Signing Flow
79
+
80
+ ```
81
+ ┌─────────────────────────────────────────────────────────────────────┐
82
+ │ TOKEN CREATION │
83
+ ├─────────────────────────────────────────────────────────────────────┤
84
+ │ │
85
+ │ 1. Build payload: │
86
+ │ payload = { │
87
+ │ agentId: "my-agent", │
88
+ │ permissions: ["wallet:create:hot", "send:hot", "fund"], │
89
+ │ exp: 1738600000000, │
90
+ │ limits: { fund: 1.0 } │
91
+ │ } │
92
+ │ │
93
+ │ 2. Encode payload: │
94
+ │ payloadStr = base64url(JSON.stringify(payload)) │
95
+ │ │
96
+ │ 3. Sign with SIGNING_KEY: │
97
+ │ signature = HMAC-SHA256(SIGNING_KEY, payloadStr) │
98
+ │ signatureStr = base64url(signature) │
99
+ │ │
100
+ │ 4. Create token: │
101
+ │ token = payloadStr + "." + signatureStr │
102
+ │ │
103
+ │ 5. Register in memory: │
104
+ │ tokenHash = HMAC-SHA256(SIGNING_KEY, token).slice(0,16) │
105
+ │ sessions.set(tokenHash, { token: payload, spentByType: {} }) │
106
+ │ │
107
+ └─────────────────────────────────────────────────────────────────────┘
108
+ ```
109
+
110
+ ### Token Validation
111
+
112
+ ```
113
+ ┌─────────────────────────────────────────────────────────────────────┐
114
+ │ TOKEN VALIDATION │
115
+ ├─────────────────────────────────────────────────────────────────────┤
116
+ │ │
117
+ │ Input: "eyJhZ2VudElkIjo...".signature │
118
+ │ │
119
+ │ 1. Split token: │
120
+ │ [payloadStr, providedSig] = token.split(".") │
121
+ │ │
122
+ │ 2. Verify signature: │
123
+ │ expectedSig = HMAC-SHA256(SIGNING_KEY, payloadStr) │
124
+ │ if (providedSig !== expectedSig) → REJECT (invalid signature) │
125
+ │ │
126
+ │ 3. Parse payload: │
127
+ │ payload = JSON.parse(base64url.decode(payloadStr)) │
128
+ │ │
129
+ │ 4. Check expiry: │
130
+ │ if (payload.exp < Date.now()) → REJECT (expired) │
131
+ │ │
132
+ │ 5. Check revocation: │
133
+ │ tokenHash = HMAC-SHA256(SIGNING_KEY, token).slice(0,16) │
134
+ │ if (revokedTokens.has(tokenHash)) → REJECT (revoked) │
135
+ │ │
136
+ │ 6. Return payload with permissions │
137
+ │ │
138
+ └─────────────────────────────────────────────────────────────────────┘
139
+ ```
140
+
141
+ ---
142
+
143
+ ## Permission Checking Flow
144
+
145
+ ```
146
+ ┌─────────────────────────────────────────────────────────────────────┐
147
+ │ PERMISSION CHECK │
148
+ ├─────────────────────────────────────────────────────────────────────┤
149
+ │ │
150
+ │ Route: POST /fund │
151
+ │ Required: "fund" permission │
152
+ │ │
153
+ │ 1. Token permissions: ["trade:all"] │
154
+ │ │
155
+ │ 2. Check admin bypass: │
156
+ │ if (permissions.includes("admin:*")) → ALLOW │
157
+ │ │
158
+ │ 3. Expand compound permissions: │
159
+ │ "trade:all" expands to: │
160
+ │ ["wallet:list", "wallet:create:hot", "wallet:create:temp", │
161
+ │ "send:hot", "send:temp", "swap", "fund", "apikey:get"] │
162
+ │ │
163
+ │ 4. Check if required permission in expanded list: │
164
+ │ "fund" in expanded? → YES → ALLOW │
165
+ │ │
166
+ └─────────────────────────────────────────────────────────────────────┘
167
+ ```
168
+
169
+ ### Compound Permissions
170
+
171
+ | Permission | Expands To |
172
+ |------------|------------|
173
+ | `trade:all` | `wallet:list`, `wallet:create:hot`, `wallet:create:temp`, `send:hot`, `send:temp`, `swap`, `fund`, `launch`, `apikey:get`, `strategy:read` |
174
+ | `admin:*` | Bypasses ALL permission checks |
175
+
176
+ ---
177
+
178
+ ## Multi-Vault Security Model
179
+
180
+ AuraWallet supports multiple vaults, each with its own encrypted seed phrase, password, and derived wallets.
181
+
182
+ ### Architecture
183
+
184
+ ```
185
+ ┌──────────────────────────────────────────────────────────────────┐
186
+ │ MEMORY (Per-Vault Sessions) │
187
+ ├──────────────────────────────────────────────────────────────────┤
188
+ │ vaultSessions: Map<string, VaultSession> │
189
+ │ ├── "vault-primary" → { mnemonic, address, solanaAddress } │
190
+ │ ├── "vault-abc123" → { mnemonic, address, solanaAddress } │
191
+ │ └── "vault-def456" → (locked - not in map) │
192
+ │ │
193
+ │ Replaces singleton unlockedMnemonic with per-vault Map │
194
+ └──────────────────────────────────────────────────────────────────┘
195
+
196
+
197
+ ┌──────────────────────────────────────────────────────────────────┐
198
+ │ FILESYSTEM (Per-Vault Encrypted Seeds) │
199
+ ├──────────────────────────────────────────────────────────────────┤
200
+ │ ~/.aurawallet/vault-primary.json ← Primary vault (migrated │
201
+ │ from cold.json) │
202
+ │ ~/.aurawallet/vault-abc123.json ← Additional vault │
203
+ │ ~/.aurawallet/vault-def456.json ← Additional vault │
204
+ └──────────────────────────────────────────────────────────────────┘
205
+ ```
206
+
207
+ ### Key Properties
208
+
209
+ | Property | Behavior |
210
+ |----------|----------|
211
+ | **Independent passwords** | Each vault has its own password; unlocking one does not unlock others |
212
+ | **Per-vault locking** | Vaults can be locked/unlocked individually via `/lock/:vaultId` and `/unlock/:vaultId` |
213
+ | **Lock all** | `POST /lock` (no vaultId) locks ALL vaults at once |
214
+ | **Hot wallet scoping** | Hot wallets are scoped to their vault; private keys are encrypted with that vault's mnemonic |
215
+ | **Primary vault compat** | The primary vault remains backward-compatible with existing `/unlock` and `/setup` endpoints |
216
+ | **Auto-migration** | On first startup, `cold.json` is automatically migrated to `vault-primary.json` |
217
+ | **Restart behavior** | Server restart clears all vault sessions (all vaults lock), consistent with existing security model |
218
+
219
+ ### Hot Wallet Encryption Scoping
220
+
221
+ When a hot wallet is created under a specific vault, its private key is encrypted using that vault's mnemonic (AES-256-GCM). This means:
222
+
223
+ - The vault must be unlocked to decrypt and use its hot wallets
224
+ - Moving a hot wallet between vaults is not supported (it is bound to its vault's seed)
225
+ - If a vault is locked, its hot wallets cannot sign transactions
226
+
227
+ ### Migration from Single Vault
228
+
229
+ Existing deployments using a single `cold.json` file are automatically migrated:
230
+
231
+ 1. On startup, if `cold.json` exists but `vault-primary.json` does not, the file is copied to `vault-primary.json`
232
+ 2. The original `cold.json` is preserved as a backup
233
+ 3. All existing hot wallets continue to work under the primary vault
234
+ 4. No user action is required
235
+
236
+ ---
237
+
238
+ ## Credential Vault Security
239
+
240
+ Credential reads follow a separate, encrypted flow:
241
+
242
+ - At rest: credential files are encrypted with a vault-derived subkey (`credential-v1:<vaultId>:<mnemonic>` hash context).
243
+ - Authorization: list/read/write are scoped with `credentialAccess.read` / `credentialAccess.write` (`*`, `vault:`, `tag:`, or credential ID).
244
+ - Field minimization: sensitive fields can be stripped by token `excludeFields` (or type defaults like `password`/`cvv`) before response encryption.
245
+ - Transport security: `/credentials/:id/read` returns ciphertext encrypted to token `agentPubkey` (RSA-OAEP; hybrid RSA+AES-GCM for larger payloads).
246
+ - Read governance: `credentialAccess.ttl` and `credentialAccess.maxReads` are enforced from memory-only session state.
247
+ - Token mint contract: every token mint path requires caller `pubkey` (`/setup`, `/unlock`, `/unlock/:vaultId`, `/auth`, `/actions/token`, approval-issued replacements).
248
+
249
+ **Audit logging:** successful credential reads are logged with credential ID, agent ID, vault ID, and returned field names only (never field values).
250
+
251
+ ---
252
+
253
+ ## Spending Limit Enforcement
254
+
255
+ ```
256
+ Human Server Memory Agent
257
+ │ │ │
258
+ │ Approve: fund limit 1 ETH │ │
259
+ ├────────────────────────────>│ │
260
+ │ │ │
261
+ │ sessions.set(tokenHash, { │
262
+ │ token: { limits: { fund: 1.0 } }, │
263
+ │ spentByType: { fund: 0 } │
264
+ │ }) │
265
+ │ │ │
266
+ │ │ POST /fund │
267
+ │ │ amount: 0.3 ETH │
268
+ │ │<───────────────────────────┤
269
+ │ │ │
270
+ │ Check permission: "fund" ✓ │
271
+ │ Get limit: 1.0 ETH │
272
+ │ Get spent: 0 ETH │
273
+ │ 0 + 0.3 <= 1.0 ✓ │
274
+ │ │ │
275
+ │ Execute transfer │
276
+ │ spentByType.fund = 0.3 │
277
+ │ ├───────────────────────────>│
278
+ │ │ │
279
+ │ │ POST /fund │
280
+ │ │ amount: 0.5 ETH │
281
+ │ │<───────────────────────────┤
282
+ │ │ │
283
+ │ 0.3 + 0.5 <= 1.0 ✓ │
284
+ │ Execute, spent = 0.8 │
285
+ │ ├───────────────────────────>│
286
+ │ │ │
287
+ │ │ POST /fund │
288
+ │ │ amount: 0.5 ETH │
289
+ │ │<───────────────────────────┤
290
+ │ │ │
291
+ │ 0.8 + 0.5 > 1.0 ✗ │
292
+ │ REJECT: exceeds limit │
293
+ │ ├───────────────────────────>│
294
+ ```
295
+
296
+ ### Limit Types
297
+
298
+ | Type | Enforced On | Description |
299
+ |------|-------------|-------------|
300
+ | `fund` | `/fund` endpoint | Cold→hot transfers |
301
+ | `send` | `/send` endpoint | Hot wallet sends (optional). Sends to cold wallet address bypass (vault return) |
302
+ | `swap` | `/swap` endpoint | Swap volume (optional) |
303
+
304
+ ---
305
+
306
+ ## Wallet Tiers
307
+
308
+ | Tier | Access | Key Storage | Use Case |
309
+ |------|--------|-------------|----------|
310
+ | **Cold** | Human only | Encrypted file (password) | Treasury, source of funds |
311
+ | **Hot** | Agent with token | DB (encrypted with seed) | Agent operations |
312
+ | **Temp** | Agent with token | DB (encrypted with seed) | Ephemeral, auto-sweep |
313
+
314
+ ### Hot Wallet Creation
315
+
316
+ ```
317
+ ┌─────────────────────────────────────────────────────────────────┐
318
+ │ HOT WALLET CREATION │
319
+ ├─────────────────────────────────────────────────────────────────┤
320
+ │ │
321
+ │ Agent (with token) → POST /wallet/create { tier: "hot" } │
322
+ │ │ │
323
+ │ ▼ │
324
+ │ Check permission: "wallet:create:hot" ✓ │
325
+ │ │ │
326
+ │ ▼ │
327
+ │ ethers.Wallet.createRandom() → Random keypair (NOT HD) │
328
+ │ │ │
329
+ │ ▼ │
330
+ │ Encrypt privateKey with cold wallet mnemonic (AES-256-GCM) │
331
+ │ │ │
332
+ │ ▼ │
333
+ │ Store in DB: { │
334
+ │ address, │
335
+ │ encryptedPrivateKey, │
336
+ │ tokenHash, ← Ownership: which token created this wallet │
337
+ │ tier: "hot" │
338
+ │ } │
339
+ │ │
340
+ └─────────────────────────────────────────────────────────────────┘
341
+ ```
342
+
343
+ ### Wallet Ownership
344
+
345
+ Agents can only access wallets they own:
346
+
347
+ ```typescript
348
+ function tokenCanAccessWallet(tokenHash, walletAccess, address): boolean {
349
+ // 1. Token created the wallet (tokenHash matches)
350
+ if (wallet.tokenHash === tokenHash) return true;
351
+
352
+ // 2. Wallet is in token's walletAccess array
353
+ if (walletAccess?.includes(address)) return true;
354
+
355
+ return false;
356
+ }
357
+ ```
358
+
359
+ ---
360
+
361
+ ## Full Request Flow
362
+
363
+ ```
364
+ Human Server Memory Agent
365
+ │ │ │
366
+ │ POST /unlock │ │
367
+ │ { encrypted, pubkey } │ │
368
+ ├────────────────────────────>│ │
369
+ │ │ Decrypt cold wallet │
370
+ │ │ mnemonic → memory │
371
+ │<────────────────────────────┤ │
372
+ │ │ │
373
+ │ │ POST /auth │
374
+ │ │ { agentId, perms, │
375
+ │ │ pubkey } │
376
+ │ │<───────────────────────────┤
377
+ │ │ Create PendingAction │
378
+ │ │ Return requestId + secret │
379
+ │ ├───────────────────────────>│
380
+ │ │ │
381
+ │ POST /actions/:id/resolve │ │
382
+ ├────────────────────────────>│ │
383
+ │ │ payload = { agentId, │
384
+ │ │ permissions, limits } │
385
+ │ │ │
386
+ │ │ sig = HMAC(KEY, payload) │
387
+ │ │ token = payload.sig │
388
+ │ │ │
389
+ │ │ sessions.set(hash, { │
390
+ │ │ token, spentByType: {} │
391
+ │ │ }) │
392
+ │ │ │
393
+ │ │ GET /auth/:id │
394
+ │ │<───────────────────────────┤
395
+ │ │ Return signed token │
396
+ │ ├───────────────────────────>│
397
+ │ │ │
398
+ │ │ POST /wallet/create │
399
+ │ │ Authorization: Bearer │
400
+ │ │<───────────────────────────┤
401
+ │ │ │
402
+ │ │ Verify HMAC signature ✓ │
403
+ │ │ Check: wallet:create:hot ✓ │
404
+ │ │ Create wallet, set owner │
405
+ │ ├───────────────────────────>│
406
+ │ │ │
407
+ │ │ POST /fund │
408
+ │ │ { to: wallet, amt } │
409
+ │ │<───────────────────────────┤
410
+ │ │ │
411
+ │ │ Verify signature ✓ │
412
+ │ │ Check: fund permission ✓ │
413
+ │ │ Check: owns wallet ✓ │
414
+ │ │ Check: amt <= remaining ✓ │
415
+ │ │ │
416
+ │ │ Sign tx with mnemonic │
417
+ │ │ Broadcast to chain │
418
+ │ │ Track: spentByType.fund │
419
+ │ ├───────────────────────────>│
420
+ ```
421
+
422
+ ---
423
+
424
+ ## Security Properties
425
+
426
+ ### What's Protected
427
+
428
+ | Attack Vector | Mitigation | Mechanism |
429
+ |---------------|------------|-----------|
430
+ | Database theft | SIGNING_KEY in memory only — tokens can't be forged | HMAC-SHA256 requires the key to produce valid signatures; DB stores only tokenHash (truncated HMAC), not the key or raw tokens |
431
+ | Token theft | Tokens expire, can be revoked, restart invalidates all | Raw token held in memory escrow only — never stored in DB. First poll claims it (second returns 410). Revocation checked in-memory Set |
432
+ | Token replay | Spending tracked per-token in memory | Each operation increments `spentByType` in the sessions Map; cumulative spend checked before execution. Tokens are static (same signature), but spending tracking prevents reuse beyond limits |
433
+ | Privilege escalation | Permissions signed in token, can't be modified | Payload is base64url-encoded and HMAC-signed; modifying any field invalidates the signature |
434
+ | Cold wallet theft | Password-encrypted, requires human unlock | Vault file encrypted with AES-256-GCM using password-derived key (scrypt). Mnemonic only enters memory after correct password |
435
+ | Hot wallet theft | Encrypted with mnemonic, ownership enforced | Private keys encrypted with AES-256-GCM using the cold wallet mnemonic; decryption requires unlocked vault. Ownership checked via tokenHash match or walletAccess array |
436
+ | Password brute force | Rate limited: 5 attempts per 15 min | Applied to `/unlock`, `/setup`, `/actions`, `/nuke`, `/backup`. Keyed by IP. Resets after window expires |
437
+ | Request spam / DoS | Tiered rate limiting | 100 req/min general, 30 req/min transactions (keyed by hashed token), 10 req/min auth. See Rate Limit Design below |
438
+ | MEV sandwich attacks | Slippage floor enforced | 0.5% minimum for admin, 1% for agents. Explicit `minOut` validated against floor. Zero slippage rejected at input validation |
439
+ | XSS via installed apps | Sandboxed iframe execution | `sandbox="allow-scripts"` (no `allow-same-origin`). App cannot access parent DOM, cookies, or localStorage. See [APPS.md](./APPS.md) |
440
+ | XSS via iframe apps | URL scheme restriction + sandbox | Hardcoded `sandbox="allow-scripts allow-forms"` (no `allow-same-origin`), only `http:`/`https:` URLs allowed |
441
+ | Adapter token exposure | Internal admin token scoped to adapter router | Signed with in-memory SIGNING_KEY, invalidated on restart. Same lifecycle as all other tokens. See [ADAPTERS.md](./ADAPTERS.md) |
442
+
443
+ ### What Restart Does
444
+
445
+ 1. New SIGNING_KEY generated (random 32 bytes) → all old tokens invalid
446
+ 2. Memory sessions cleared → spending tracking reset
447
+ 3. Revocation list cleared → (tokens invalid anyway)
448
+ 4. Cold wallet locks → requires password to unlock
449
+ 5. Agents must request new approval
450
+
451
+ **This is intentional security, not a bug.**
452
+
453
+ ---
454
+
455
+ ## Design Rationale
456
+
457
+ ### Why memory-only auth?
458
+
459
+ The hard boundary between database and runtime is the foundation of the security model. The database stores display data (UI, logs, audit trail), while all auth decisions happen against in-memory state. This means a stolen database — the most common attack surface — yields nothing actionable. An attacker cannot forge tokens, cannot reconstruct the SIGNING_KEY, and cannot access encrypted hot wallet keys (which require the cold mnemonic, also in memory only when unlocked).
460
+
461
+ ### Why 32 bytes for SIGNING_KEY?
462
+
463
+ RFC 2104 recommends HMAC keys be at least as long as the hash output. HMAC-SHA256 produces 32 bytes, so the SIGNING_KEY is 32 bytes of `crypto.randomBytes()`. This provides 256 bits of entropy — computationally infeasible to brute-force.
464
+
465
+ ### Why restart invalidation is a feature
466
+
467
+ Restart invalidation implements the fail-closed principle. If the server process is compromised, killed, or crashes, all auth state is wiped. There is no way for stale tokens to persist across process boundaries. This eliminates an entire class of token persistence attacks and ensures every session begins with a clean, human-approved auth state.
468
+
469
+ ### Why RSA-OAEP for password transport
470
+
471
+ Even on localhost, HTTP traffic is observable by other processes (proxy tools, malware, debugging middleware). RSA-OAEP encrypts the vault password before it leaves the browser, so a network observer sees only ciphertext. The RSA keypair is ephemeral (regenerated on restart), and RSA-OAEP provides semantic security — encrypting the same password twice produces different ciphertext.
472
+
473
+ ---
474
+
475
+ ## Rate Limit Design
476
+
477
+ | Tier | Limit | Endpoints | Key | Rationale |
478
+ |------|-------|-----------|-----|-----------|
479
+ | **Brute-force** | 5 / 15 min | `/unlock`, `/setup`, `/actions`, `/nuke`, `/backup` | IP | Protects password-based operations from automated guessing |
480
+ | **Auth** | 10 / min | `/auth` | IP | Prevents token request flooding while allowing legitimate multi-agent setups |
481
+ | **Transaction** | 30 / min | `/send`, `/swap`, `/fund`, `/launch` | Hashed token | Per-agent throttle; prevents a single agent from monopolizing chain operations |
482
+ | **General** | 100 / min | All other endpoints | IP | Baseline DoS protection for informational endpoints |
483
+
484
+ Rate limits are configurable via the defaults API (`PATCH /defaults`) and take effect immediately without restart (hot-reloadable).
485
+
486
+ ---
487
+
488
+ ## Database Security Model
489
+
490
+ | Table | Encrypted? | What attacker gains from stolen DB |
491
+ |-------|------------|-----------------------------------|
492
+ | `AgentToken` | No | Token metadata (agentId, permissions, expiry) — but NOT the raw token or SIGNING_KEY. Cannot forge or replay tokens |
493
+ | `HotWallet` | Yes (AES-256-GCM with cold mnemonic) | Ciphertext of private keys — cannot decrypt without the cold mnemonic (which is only in memory when unlocked) |
494
+ | `HumanAction` | No | Pending/resolved action history — no secrets, no tokens |
495
+ | `ApiKey` | No | Third-party API keys (Alchemy, Anthropic) — exposure risk, but cannot access wallet funds |
496
+ | `Log` | No | Audit trail — addresses, amounts, timestamps. No private keys or tokens |
497
+ | `Vault files` | Yes (AES-256-GCM with password-derived key) | Encrypted seed phrase — cannot decrypt without the vault password |
498
+
499
+ **Key takeaway:** The database alone cannot forge auth tokens, decrypt hot wallet keys, or steal funds. The SIGNING_KEY (token forgery) and cold mnemonic (key decryption) exist only in server memory.
500
+
501
+ ---
502
+
503
+ ## Permission & Error Reference
504
+
505
+ For the full permissions table, compound permission expansions, route→permission mapping, and error responses, see [AUTH.md](./AUTH.md).
506
+
507
+ ---
508
+
509
+ ## Temporary Action Tokens
510
+
511
+ Apps can request per-operation human approval via `POST /actions`. On approval, a temporary scoped token is created with short TTL (default 60s).
512
+
513
+ ```
514
+ App calls AuraApp.action({...})
515
+ → POST /actions (requires action:create permission)
516
+ → HumanAction created (type: 'action')
517
+ → Human approves via dashboard / Telegram / webhook
518
+ → Temp token created (short TTL, scoped permissions/limits)
519
+ → App polls GET /auth/:requestId?secret=... → receives temp token
520
+ → App uses temp token to call endpoint directly
521
+ → Token expires after TTL
522
+ ```
523
+
524
+ ### Security Properties
525
+
526
+ | Property | Guarantee |
527
+ |----------|-----------|
528
+ | No privilege escalation | `admin:*` and `action:create` blocked in requested permissions |
529
+ | Short TTL | Default 60 seconds — app must use token quickly |
530
+ | Scoped permissions | Temp token only has the specific permissions requested |
531
+ | Scoped limits | Spending limits enforced on the temp token |
532
+ | Memory-only auth | Same SIGNING_KEY model — restart invalidates everything |
533
+ | Human override | Approver can tighten limits/walletAccess before approval |
534
+ | Single retrieval | Raw token held in memory escrow, claimed once on first poll (second poll returns 410). DB only stores tokenHash |
535
+
536
+ ---
537
+
538
+ ## Best Practices
539
+
540
+ See [BEST-PRACTICES.md](./BEST-PRACTICES.md) for guidance on password management, spending limits, token hygiene (humans), permission scoping, error handling patterns (agents), and route auth patterns, security checklists (developers).
@@ -0,0 +1,61 @@
1
+ # Aura Open Protocol (.aura) v1
2
+
3
+ ## Scope
4
+ Vendor-neutral `.aura` parsing + resolution contract.
5
+
6
+ ## Grammar (v1)
7
+ - UTF-8, optional BOM ignored, CRLF normalized to LF.
8
+ - Statements: blank, full-line comment (`#`), assignment (`KEY = VALUE`).
9
+ - Key regex: `^[A-Z][A-Z0-9_]{0,127}$`.
10
+ - Duplicate keys: `E_PARSE_DUPLICATE_KEY`.
11
+ - Value forms:
12
+ - bare string
13
+ - quoted string (`\"`, `\\`, `\n`, `\r`, `\t`, `\uXXXX`)
14
+ - provider ref `${provider://resource?query}`
15
+ - var ref `${KEY}`
16
+ - Inline trailing comments are not supported in v1.
17
+
18
+ ## Parse output contract
19
+ `parse(text)` returns:
20
+ - `version: "aura.v1"`
21
+ - `nodes[]` with required `type` and `loc`
22
+ - assignment nodes also include `keyRaw`, `keyNorm`, `valueType`, `valueRaw`, `valueNorm`
23
+
24
+ ## Validation + normalization contract
25
+ `validate(doc)` returns deterministic lexical ordering by key:
26
+ - `normalized.entries[]`
27
+ - entry fields: `key`, `value`, `origin`, `dependencies`, optional `providerRef`
28
+
29
+ ## Resolver determinism
30
+ - Fixed error precedence:
31
+ 1) parse
32
+ 2) validate
33
+ 3) reference graph
34
+ 4) provider resolution
35
+ 5) merge/output policy
36
+ - Bounded limits:
37
+ - max depth: 32 (`E_RESOLVE_DEPTH_EXCEEDED`)
38
+ - provider budget: 256 (`E_RESOLVE_PROVIDER_BUDGET`)
39
+ - default provider timeout: 5000ms
40
+
41
+ ## Compatibility matrix
42
+ - Supported baseline: spec 1.x + parser 1.x + provider API 1.x
43
+ - Unknown major spec: `E_COMPAT_SPEC_UNSUPPORTED`
44
+ - Provider API major mismatch: `E_COMPAT_PROVIDER_API`
45
+
46
+ ## Trust/signature model (v1)
47
+ - JCS canonicalization for signed payload.
48
+ - Signature algorithm: `ed25519` only.
49
+ - Required envelope fields:
50
+ - `algorithm`, `keyId`, `sig`, `createdAt`, `payloadSha256`
51
+
52
+ ## Error envelope
53
+ All failures should expose:
54
+ - `code`, `category`, `severity`, `message`, `retryable`
55
+ - optional `details`, `loc`
56
+
57
+ Code families:
58
+ - `E_PARSE_*`, `E_VALIDATE_*`, `E_RESOLVE_*`, `E_POLICY_*`, `E_TRUST_*`, `E_COMPAT_*`
59
+
60
+ ## Canonical fixtures
61
+ See `docs/specs/fixtures/` for v1 parse fixtures.