Skip to content

Aikido#6

Merged
insuT0ver merged 10 commits into
mainfrom
aikido
Jun 26, 2026
Merged

Aikido#6
insuT0ver merged 10 commits into
mainfrom
aikido

Conversation

@insuT0ver

Copy link
Copy Markdown
Contributor

No description provided.

insuT0ver and others added 10 commits June 24, 2026 09:01
…lities

- Write credentials to ~/.aikido-creds.json (chmod 600) instead of passing as env vars in .claude.json, preventing accidental exposure through environment dumps
- Add shellEscape() helper and apply it to all paths in shell commands, preventing injection attacks when workspace/file paths contain special characters

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@insuT0ver
insuT0ver merged commit c273693 into main Jun 26, 2026
1 check passed
@insuT0ver
insuT0ver deleted the aikido branch June 26, 2026 15:55
insuT0ver added a commit that referenced this pull request Jun 29, 2026
* feat: verwijder Sparky vLLM-integratie volledig (#4)

Verwijdert alle Sparky-gerelateerde code en configuratie:
- huddle.ps1: Start-SparkyProxy functie, variabelen en --add-host flag
- .ai/opencode/opencode.json: sparky-provider en modelregistratie
- .ai/opencode/AGENTS.md: alle Sparky-instructies
- .ai/README.md: Sparky-vermeldingen

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* feat: verbeter gateway block response met rijke JSON-foutinfo (#2)

De proxy geeft nu een gestructureerde JSON-response bij geblokkeerde requests:
- error: REQUEST_BLOCKED_BY_HUDDLE (machine-leesbaar)
- blockedEndpoint, reason, actionRequired
- devcontainerId voor traceerbaarheid
- huddlePortal URL voor directe navigatie
- x-huddle-blocked header voor snelle detectie door clients

send403, rejectSocket en MITM-padblocking allemaal bijgewerkt.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* feat: voeg resource caps toe voor devcontainers (#3)

Nieuwe memory- en CPU-limieten kunnen worden ingesteld bij het starten
van devcontainers of als globale standaard in de instellingen.

- docker.ts: parseMemoryBytes/parseCpuQuota helpers; StartParams.memory/cpus;
  HostConfig.Memory/CpuQuota/CpuPeriod worden doorgegeven aan Docker
- api.ts: POST /api/docker/start accepteert memory en cpus; GET/POST
  /api/settings beheert defaultMemory en defaultCpus
- api.service.ts: HuddleSettings bijgewerkt naar defaultMemory/defaultCpus
- settings.component.ts: UI voor globale resource limieten

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* feat: vervang hardcoded AI-mounts door generieke foldermappings (#5 #6)

Verwijdert de vaste Claude/Codex/OpenCode provider-mount logica en vervangt
die door een configureerbare folder_mappings tabel. Operators kunnen via de
Instellingen-pagina bindmounts of named volumes toevoegen, bewerken en
verwijderen.

Verwijdert ook de hardcoded AI_CONFIG_DIR en de COPY .ai/… stappen uit de
Dockerfile. De .ai-map wordt niet meer ingebakken in het image maar als
gewone runtime bindmount aangeboden (standaard host_path = /.ai).
De .ai-map is uit git-tracking verwijderd.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* feat: voeg Docker host port approval flow toe met poortbeheer UI (#7)

Containers die een host-poort willen binden worden onderschept door de
socket-proxy. Niet-goedgekeurde poorten worden geblokkeerd met HTTP 403.
Operators keuren poorten goed via de Docker-tab op de containerdetailpagina
of via de Docker Access-pagina. Backend: GET/POST/DELETE
/api/containers/:name/ports.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* clean up

* docs: herschrijf README met uitgebreide getting started en uitleg

- Vervang PS1-script door npm run build/start/install commando's
- Voeg sectie toe voor containers openen in JetBrains en VS Code
- Leg AI-configuratie (.ai/) uit met Windows→container padmapping
- Vervang Freshdesk-voorbeeld door Aikido Security extensie
- Voeg firewall-beheer sectie toe

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* feat: standaard resource limieten 8g/2cpu, hernoem Audit Logs naar Network Logs, fix rogue-status voor gestopte containers

- Nieuwe devcontainers krijgen standaard 8 GB RAM en 2 CPU tenzij de operator een andere waarde heeft ingesteld
- "Audit Logs" hernoemd naar "Network Logs" in sidebar, paginatitel en container-detail
- Dashboard markeert gestopte containers nu correct als "Stopped" i.p.v. "Rogue"

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
insuT0ver added a commit that referenced this pull request Jul 16, 2026
* feat(gateway): security-hardening (findings #1#15, excl. Aikido)

Squashed hardening work on top of main (operator-auth + source-IP-gate
removal already landed via #47). Internal review/design docs and the Aikido
extension changes (findings #6/#14) intentionally left out of this branch.

- #1/#2 socket-proxy HostConfig allowlist: reject VolumesFrom, DeviceCgroupRules,
  DeviceRequests and the device family (host/daemon takeover, raw-disk access).
- #3 CONNECT hostname canonicalization + COLLATE NOCASE so casing can't bypass
  an exact deny carved out of a wildcard allow.
- #7 path-allowlist normalization (fail-closed on ../ and ..%2f, segment
  boundaries), normalized path forwarded upstream.
- #8 named-volume ownership check (huddle.parent) + GET /volumes filtered.
- #9 folder-mapping column allowlist kills the JSON-key SQL injection; route
  returns 400/404 instead of 500.
- #11 extension-bundle SHA-256 integrity check before extraction (allowlist).
- #12 token placeholder bound to the requesting container (timing-safe) + TTL;
  no shared 'unknown' bucket; redacted from the audit body.
- #13 PTY multi-attach logs attach:owner vs attach:join(N) so a join is never
  silent (regression test added).
- #15 IDE credential channel: VS Code Machine settings (workspace trust, no
  auto-tasks, no local terminal, null credential env) + a container-side guard
  that strips the forwarded git credential.helper from /etc/gitconfig and
  ~/.gitconfig, tears down the forwarded GPG/SSH/askpass sockets, and re-applies
  on inotify events (fallback poll). JetBrains gets the shared env/socket scrub.
  Verified live: git push and `git credential fill` no longer obtain host creds.
- e2e: authenticate with HUDDLE_OPERATOR_TOKEN; split devcontainer→API into
  proxy path (403) and direct path (401); targeted pre-flight on auth misconfig.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* fix(gateway): address Aikido review on POST /api/rules

Two Aikido findings on the finding-3 domain handling:
- non-string `domain` (truthy but not a string) passed the truthiness check and
  then threw on .toLowerCase() → 500. Require typeof === 'string' → clean 400.
- storing the domain lowercased mutated the value clients get back ("may break
  clients expecting original casing"). It was redundant anyway: matching is
  already case-insensitive (COLLATE NOCASE in db.ts + canonicalizeHost/matchDomain).
  Store the domain as provided; the requested-row cleanup DELETE gets COLLATE
  NOCASE so it still matches the lowercase requested rows the proxy creates.

Finding #3 stays closed; echo-back to clients is preserved.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* fix(test): correct finding-3 e2e expectation for HTTPS CONNECT deny

The finding-3 casing test expected a 403 from `curl https://gist.github.com`,
but a host-level HTTPS deny refuses the CONNECT tunnel (rejectSocket → 403 on
the CONNECT response). curl then reports http_code '000' — the 403 lives in
http_connect_code, not http_code (unlike the plain-HTTP deny path, which does
surface 403). So the request came back '000', not '403', and e2e failed.

Assert '000' for both the exact and the capitalized host: a refused CONNECT is
the correct, deterministic signal that the deny holds (no upstream egress
needed). If casing bypassed the deny, the host would match the wildcard allow
and the CONNECT would be accepted — not '000'. Path-mode 403 assertions
(finding 7) are unchanged: those keep the tunnel open and return 403 inside the
MITM'd session.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
TijsVK added a commit to TijsVK/huddle that referenced this pull request Jul 18, 2026
…hz plugin

Adversarial review found the socket-proxy filter (dind-filter.ts) bypassable two
ways, both verified live:
  1. the devcontainer mounted the dir holding BOTH the filter's docker.sock AND
     the raw inner.sock — `curl --unix-socket inner.sock` skipped the filter.
  2. even after splitting them, a nested container could symlink a shared
     workspace path to the sidecar's socket dir and bind through it; dockerd
     follows symlink bind sources, so a lexical bind guard can't stop it.

Root cause: putting a filter IN FRONT of an unfiltered daemon socket always
leaves that socket reachable. Fix: enforce the guard IN the daemon via
`--authorization-plugin=huddle-authz` (gateway/src/dind-authz.ts). dockerd calls
the plugin before every request on its single socket, so there is no unfiltered
path to reach (findings infosupport#1/infosupport#2 gone) and dockerd handles stream/hijack/chunk
framing natively (the old half-open/grpc/buffering complexity — findings infosupport#4/infosupport#5/infosupport#6
— dissolves).

Topology: sidecar dockerd listens on docker.sock (mounted into the devcontainer);
the gateway serves huddle-authz.sock, mounted into the sidecar at
/run/docker/plugins. No inner.sock. Under authz all binds are safe (docker.sock is
authz-guarded), so the DinD bind guard is dropped — Ryuk / docker-outside-of-
docker work.

Also closes review findings infosupport#3 (MaskedPaths/ReadonlyPaths unmask — deny when the
critical /proc/kcore mask or /proc/sysrq-trigger read-only path is removed; the
CLI sends these populated by default, so only an unmask is refused), infosupport#7
(privileged exec-create), infosupport#8 (any non-default seccomp/apparmor, not just literal
unconfined). validateDindEscape simplified to the kernel/device policy; the pure
host-config-policy.ts is reused by the plugin. The compat harness (lib.sh) now
runs the real plugin via authz-runner.mjs.

Verified live: no inner.sock; raw privileged create over docker.sock → 403;
symlink-bind bypass closed; privileged/device/exec denied; MaskedPaths unmask
denied; compose/buildx/exec/host-path-binds/Ryuk all work. 239 unit tests green
(dind-authz.test.ts replaces dind-filter.test.ts).
TijsVK added a commit to TijsVK/huddle that referenced this pull request Jul 18, 2026
…ty mode has no bindable host path under the allowlist)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant