TR · EN · security.txt · Audit trail
Güvenlik / Security
TR — kır, ödeyelim
Verax 0.4.0 veya sonrası, README’deki gibi verax install ile kurulmuş ve varsayılan politikayla çalışırken, ajanın çalıştığı hesaptan (yönetici değil) şu üçünden birini yapabilen her geçerli rapora 100 dolar ödüyoruz: politikanın reddettiği bir çağrıyı geçirmek, karar kaydı bırakmayan bir çağrı çalıştırmak, servisin kodunu, anahtarlarını ya da defterini değiştirmek. Toplam bütçe 500 dolar; bitince teklif sona erer ve bu sayfa ile SECURITY.md bunu yazar. Kapsam dışı olanlar ve bildirim yolu SECURITY.md’de.
TR — kim düşman varsayılır
Beyin (MCP istemcisi) düşmandır: herhangi bir araç adı, argüman, tekrar ve sosyal istem gönderebilir. Araç sunucusu düşmandır: yalan söyleyebilir, asılı kalabilir, beyan edilen etkinin dışına yazabilir. İstem enjeksiyonu politikayla süzülmez. Politika araç adını ve jetonun kapsamlarını görür; argümana iki yerde bakar: spend (para birimi, çağrı başı tavan, alıcı listesi, günlük limit) ve message.send alıcısının alan adı. 0.8.0'dan beri politika veri sınıfı ve dosya türü de adlandırabilir: çağrının sınıflarında maskele, yerelde tut ya da engelle varsa argümanları, aracın sonuç sınıflarında maskele ya da engelle varsa sonucu taranır. Bunlar yoksa başka argüman metnini ya da araç sonucunu görmez.
İmzalı olan: karar (allow, deny or defer), politika cümlesinin hash’i, varsa inputs belgesi, etki satırı, çağrı anındaki receipt. Tanık varsayılan olarak self; verax witness ikinci bir süreç olarak koşarsa etki satırı same-org olur ve dayanıklı checkpoint imzalanır. O süreç aynı makinede, aynı operatörün altındadır: ayrı anahtar, ayrı güven alanı değil. Pin varsayılanı gövdenin kendi kayıt anahtarıdır; dış kök değildir. Üçüncü taraf doğrulama iddiası yoktur.
Bu sayfa 18 Eylül 2026’ya kadar üç şeyi “yok” diye yazıyordu; kodda üçü de vardı. Kiracı sınırı var: bellek ve gelen kutusu tenants/<tenantKey>/ altında durur, anahtar SHA-256 {iss, sub} (varsa tenant / org ile), ve başka kiracının kimliği gövdesiz imzalı bir deny ile cevaplanır. Yeniden deneme var: aynı _ref bir kez icra edilir, kalanlar tekrar oynatılır, retry bugünkü politika ve kapsamla yeniden değerlendirilir. Tanık yukarıda. Üçü de 0.1.2’de düzeltme gördü; hangi satırın hangi sürümde geldiği ve hangi testin tuttuğu STATUS tablosunda.
Açık boşluklar
- Varsayılan olarak kaydı tutan ve imzalayan aynı sistemdir. Checkpoint'ler başkasının işlettiği bir şeffaflık servisine kaydedilebilir ve aşağıdaki bir sunucu kendi etki satırlarını imzalayabilir; ikisi de varsayılan değildir. Bağımsız denetim yapılmadı.
- Her müşterinin kaydı ayrı durur; başkasınınkini isteyen imzalı ret alır. Sınır aynı disk, aynı süreç ve aynı operatörde durur; iki canlı müşteri aynı gövdeyi paylaşana kadar kanıtlanmış değildir.
- 0.4.7 ile gövde nabzını boştayken de 10 saniyede bir yazar; verax watch eksik ya da bayat nabzı suskunluk sayar ve gövdeyi durdurabilir. Tek makinede izleyici operatörle aynı güveni paylaşır: o makine tek kopyayı ve izleyicisini birlikte durdurursa tek makinedeki defter suskunluğu “hiçbir şey olmadı”dan yine ayırt edilemez; çalışma süresi kanıtlanmaz.
- Yükler düz metin; şifreleme tasarlanmadı.
- Eski defter parçalarını tutma, taşıma ve silme tasarlandı, yapılmadı. Hiçbir şey kendiliğinden silinmez.
- _inputs isteğe bağlı; policy.requireInputs açılmadıkça zorunlu değil ve yayınlanan politikada kapalı. Beyansız bir çağrı inputs: [] olarak kaydedilir.
- Allow ile etki arasında çökme olursa çağrı outcome-unknown döner. Araca ulaşan koşuyu ulaşmayandan ayıramaz; onaylı bir çağrı yeniden onay isteyebilir.
- Tekrarlanan bir etki ya da geç gelen bir olay için davranış tasarlanmadı.
- spend yetkilendirir ve kaydeder; gövde para taşımaz. Kayıtlı harcamalar kart ekstresiyle karşılaştırılır; şimdiye kadar bir canlı satır eşleşti (10,00 TRY, 6 Eylül 2026).
- Cedulon'un EffectRow'u hâlâ resultHash taşıyamaz; onu attestation taşır.
- Maskeleme değerin kendisini gizler; çevresindeki metinden tahmin edilmesini engellemez.
EN — break it, and we pay
Against Verax 0.4.0 or later, installed with verax install as the README describes and running the default policy, we pay USD 100 for each valid report of a way for the account the agent runs as (not an administrator) to do one of three things: get a call its policy refuses allowed, run a call that leaves no decision record, or change the service's code, keys or ledger. The budget is USD 500 in total; when it is spent, the offer ends and this page and SECURITY.md say so. What is not covered, and how to report, is in SECURITY.md.
EN — who is assumed hostile
The brain (MCP client) is hostile: it may send any tool name, any arguments, any replay, and any social prompt. The tool server is hostile: it may lie, hang, or write outside the declared effect. Prompt injection through tool results is not filtered by policy. The policy sees the tool name and the token's scopes, and reads arguments in two places: spend (currency, cap per call, payee list, daily limit) and the recipient host of message.send. Since 0.8.0 a policy can also name data classes and file types: a call's arguments are scanned when its classes include mask, local or block, and a tool's result when its result classes include mask or block. Without them the policy reads no other argument text and no tool result.
What is signed: the decision (allow, deny or defer), the policy sentence hash, an inputs document when present, the effect row, and a receipt at call time. The witness is self by default; when verax witness runs as a second process, the effect row is same-org and a durable checkpoint is signed. That process sits on the same host under the same operator: a separate key, not a separate trust domain. The default pin is the body's own record key, not an external root. There is no claim of third-party verification.
Until 18 September 2026 this page called three things missing that the code already had. There is a tenant boundary: memory and inbox live under tenants/<tenantKey>/, the key is SHA-256 of {iss, sub} plus a tenant or org claim when present, and another tenant's id is answered with a signed deny and no body. Retry is designed: one _ref executes once and the rest replay, and a retry is evaluated against the policy and scopes in force now. The witness is above. All three were corrected in 0.1.2; which row shipped in which version, and the test that holds each one up, are in the STATUS matrix.
Open gaps
- By default the same system keeps the record and signs it. Checkpoints can be registered with a transparency service someone else runs, and a downstream server can sign its own effect rows; neither is on by default. No independent audit has been done.
- Each customer's records are kept apart, and asking for another's gets a signed refusal. The boundary stops at the same disk, the same process and the same operator, and it is unproven until two live customers share one body.
- Since 0.4.7 the body rewrites its heartbeat every 10 seconds, idle included, and verax watch treats an absent or stale beat as silence and can halt the body. On a single host the watcher shares the operator's trust: silence on a single-host ledger still cannot be told from nothing happened if that host stops both the only copy and its watcher, and no uptime is attested.
- Payloads are plaintext; encryption is not designed.
- Keeping, moving and dropping old ledger pieces is designed, not implemented. Nothing is deleted automatically.
- _inputs is optional unless policy.requireInputs is on, and it is off on the shipped policy. A call with no declaration stores inputs: [].
- After a crash between the allow and the effect the call answers outcome-unknown. It cannot tell a run that reached the tool from one that did not, so an approved call may need a fresh approval.
- What happens to a duplicate effect or a late event is not designed.
- spend authorizes and records; the body does not move money. Recorded spends are reconciled against a card statement export; one live row has been matched so far (10.00 TRY, 6 September 2026).
- Cedulon's EffectRow still cannot hold resultHash; the attestation does.
- Masking hides the value itself; it does not stop the value being guessed from the text around it.