Known limitations
If you hit something that is not on this page, we'd like to hear about it!
No zero-egress deployment
What it means. Your cluster must reach api.gen0sec.com on port 443. That connection carries
threat intelligence, GeoIP, ML models and IDS rules, which are licensed upstream data that is in no
artifact we ship.
What you can remove. All dependency on Gen0Sec-hosted registries. The offline bundle method mirrors every image and chart into your own registry, so your cluster pulls nothing from us.
What you cannot remove. The runtime connection. There is no supported configuration with zero cluster egress.
If your policy forbids all egress, please contact us.
Our registry challenges pulls that send no user agent
By design on our side, and it can decide which install method you use.
Symptom. Every image pull from registry.gen0sec.com returns 403 with a CAPTCHA challenge, and
pods sit in ImagePullBackOff. A manual docker pull or skopeo copy from the same node succeeds.
That discrepancy is the whole diagnosis. If the CLI works and the kubelet does not, this is it.
Cause. On some Kubernetes distributions, the component that services the kubelet's pull sets no
User-Agent header. Go's net/http then sends its own default, Go-http-client/1.1, and our edge
treats that as a scanner signature and issues a challenge. A kubelet cannot solve a CAPTCHA, so the
pull never succeeds and never will.
It is not your credentials, not the pull secret, not TLS, and not an allowlist.
What passes and what does not
Measured against our registry:
| User-Agent | Result |
|---|---|
containerd/1.7.0 | 200 |
containerd/v2.1.4 | 200 |
docker/29.4.0 | 200 |
curl/8.7.1 | 200 |
skopeo/1.24.0 | 200 |
Go-http-client/1.1 | 403, challenged |
Go-http-client/2.0 | 403, challenged |
containerd's own user agent is fine. Any real one is. The failure is specifically the absence of a
user agent, which Go turns into Go-http-client.
Confirming it
The blocked response identifies what it matched:
"user_agent": "Go-http-client/1.1", "ja4_fingerprint": null, "captcha_validated": false
Compare a manual pull against what the kubelet gets:
# on the node: succeeds, because the CLI sends its own user agent
skopeo inspect docker://registry.gen0sec.com/gen0sec/auth-api:0.2.0
# what the kubelet sees
kubectl -n gen0sec describe pod <pod> | grep -A3 Failed
Success from the CLI plus 403 from the kubelet confirms it.
Two ways forward
Option 1: use the offline bundle method. Nothing to configure on your nodes, and your own registry does not inspect user agents. See Prepare the artifacts.
Option 2: make the pull path send a user agent, on every node.
If you cannot change container runtime configuration on your nodes, whether by policy or because your distribution manages it, use the offline bundle method. This constraint forces that choice, and it is better made before you start than at the first failed pull.
The relay cannot use an explicit egress proxy
Symptom. You set HTTPS_PROXY on the relay. Nothing changes, and nothing errors.
Cause. Every HTTP client in the platform builds its own transport without proxy support, so
HTTP_PROXY and HTTPS_PROXY are ignored inside the cluster. This is by design.
What works instead.
| Option | Notes |
|---|---|
Allow api.gen0sec.com:443 directly | One firewall exception that bypasses the proxy |
| Redirect transparently at the network layer | The client does not need to be proxy-aware |
A TLS-intercepting proxy also cannot work: the charts expose no way to mount a CA bundle into the platform containers, and the relay rejects the intercepted certificate.
The object store bucket is not created for you
Symptom. Services start and then fail to read or write the object store. download-api answers
500 NoSuchBucket.
Cause. Nothing in the charts creates the bucket.
What to do. Install step 5 creates it. It is a first-class step, not an optional one.
Three services report readiness from a weaker probe
download-api, ids-rules-api and service-graph-api serve a richer /status/healthz and, in doing
so, never register /status/readyz. Requesting it returns 404, so a readiness probe pointed at it
fails forever while liveness stays healthy, and the pod sits at 0/1 with zero restarts.
What that means for you. Do not repoint those services at /status/readyz. It will fail.
Helm never upgrades CRDs
Not our defect, but it will bite you on the first upgrade that contains CRDs, so it is here.
Helm installs a chart's CRDs on first install and ignores them from then on. An upgrade that ships a new CRD schema fails with a server-side-apply error, or silently rejects new fields.
Upgrade applies them by hand as step 1. Do not skip it.
Kafka volumes survive an uninstall
deleteClaim: false is deliberate, so helm uninstall leaves the Kafka volumes behind. Reinstalling
against them produces Invalid cluster.id ... Expected X, but read Y, because the new cluster
generates a new identity.
Delete the volume claims first, or restore the original cluster. See Kafka will not start.
The audit log needs new partitions after two years
The upgrade to v0.2.0 creates monthly audit log partitions for the previous month and the next 24.
Nothing creates later ones yet. Past that, audited actions fail with
no partition of relation "audit_log" found for row, and rule changes made through the API are lost.
Create partitions ahead of time, as the database superuser:
SELECT create_audit_log_partition(date '2028-11-01');
The audit log is never pruned
It is append-only and kept indefinitely, and the application cannot delete from it. To remove old
history, back up and then drop a monthly partition (audit_log_YYYY_MM) as the superuser.
Emails are sent as "My App"
Invitation and password-reset emails carry the sender name My App, whatever you configure. Only the
address, HOST_ALIAS_EMAIL, is yours.
New WAF rule functions need current agents
regex_replace() and http.request.raw_path validate from v0.2.0. The rule language is generated
from Synapse 0.8.5, and agents on an older version may not evaluate a rule that uses them. Update
agents before you rely on either.
Rule changes do not reach agents
Creating, editing or deleting a rule, or switching a managed rule on or off, saves the change but does not regenerate the configuration agents fetch. The fleet keeps enforcing the previous rules. The rule write succeeds and the dashboard shows nothing; PostgreSQL logs a warning per write:
WARNING: notify_config_generator: POST to http://g0s-config-generator... failed: permission denied for function http_post
The database trigger that asks for the regeneration lacks the privileges to make the call. Restore them as the database superuser:
ALTER FUNCTION public.notify_config_generator() SECURITY DEFINER;
ALTER FUNCTION public.notify_config_generator() SET search_path = public, net, pg_temp;
Rules saved before that are picked up by the next rule change in the same workspace.
Managed WAF rules do not work
The dashboard cannot list managed WAF rules or switch them on or off, managed WAF rules are never sent
to agents, and changing one fails with column s.waf_rules_managed_id does not exist. The database
names the column rule_managed_id, and everything that reads it expects waf_rules_managed_id.
Creating your organization ends on a page not found
Right after first-run setup creates the organization, the dashboard sends you to
/<workspace>/check-workspace, which does not exist. Nothing is wrong with the organization. Remove
/check-workspace from the address to reach the workspace overview.
The overview offers Threats
The overview shows a Threats card, but the Threats module is not part of the self-hosted release and opening it fails. Ignore the card.
Migration force means the opposite of what people expect
migrate force <version> marks that version applied and continues with the next one. To re-run a
migration that failed, force the version before it.
Migrations are not idempotent. Forcing to the wrong version re-runs DDL that already exists and fails
with already exists.
Example: if 20261004150000 fails, run force 20261004120000.