Violet RE logo: two offset V glyphs on a dark tile Violet REStatic reverse engineering

statusnot openreleaseexpected Spring 2027

violetre.io

Decompile binaries. Read the code. Check it for known weakness types.

Send an executable or a mobile package you own or are authorised to assess. Violet RE recovers readable source, then checks that source for known vulnerable patterns. Targets are never executed on the public tier. The analysis is static, start to finish.

The service is not open. Uploads are not being accepted, and accounts cannot be created.

sample.zip 207 bytes offset / bytes / ascii

An archive holding the worked example further down this page, dumped byte for byte. The first four bytes, 50 4b 03 04, are the local file header signature every ZIP starts with: read back as a little-endian integer that is 0x04034B50, the constant the example function compares against. Illustration of the material, not a product screen.

  • Readable source Decompiled and deobfuscated, with every proposed rename checked against a language-specific equivalence gate before it is accepted.
  • Vulnerability checks Known weakness types, such as injection and path traversal, each finding with its conditions, confidence and limits. Guided by a database of CVE, NVD and CISA KEV records.

.renames

How a rename gets accepted.

Most deobfuscation tools guess identifier names and hope. Violet RE puts every proposal through a gate that is specific to the language, and records what happened.

The worked example below is one decompiled Python function, first as the decompiler emitted it, then after renaming. Seven renames were proposed. Six compiled to identical bytecode and were kept. One did not, so the original name stands and the report records which gate rejected it.

original_source/zip_entry.py decompiler output
violet_source/zip_entry.py violet reconstruction
gate applied
Python bytecode equivalence
proposals accepted
6 of 7
rejected by the gate
1, name unchanged
  • Obfuscated identifier, as emitted
  • Rename accepted by the gate
  • Rename rejected, original kept

In the example, six identifiers are renamed and the seventh, _0x3d, is left as the decompiler emitted it. Both files ship: the raw decompiler output and the Violet reconstruction are separate artefacts in the same package, alongside the transformation record and the rejection log. Diff them yourself.

Python
Bytecode equivalence. The renamed version must compile to identical bytecode.
C, C++, Java
Structural equivalence via Tree-sitter. The syntax tree after renaming must match.
every language
Per-proposal accept and reject tracking, surfaced in the report, including which gate rejected each proposal.

These are gates, not proofs. A gate checks equivalence under the rules of one language. It is not a claim of semantic understanding, and the report says where understanding stops.

.locate

Finding a function in a stripped binary.

A gate only has something to judge once you know what the function is. The name sqlite3_str_vappendf is in neither of the two SQLite builds we compiled for the published teardown. The function at 0x100002778 was identified three ways, and none of them needs the source.

three checks, one function SQLite 3.39.1, stripped arm64 Mach-O, 20 September 2026

Three independent lines of evidence, all agreeing, none of them requiring a symbol table. Done by hand with rabin2, radare2 and python3, every command printed in the analysis writeups. The released source sits beside these binaries in our fixture directory and was used afterwards to confirm what the disassembly showed. This is an analyst reading a binary, not a product screen.

one rare string
The %Q handler emits the literal (NULL), with parentheses, when the argument is null. That exact spelling occurs once in the file, and there is exactly one cross-reference to it, in the function beginning at 0x100002778.
the format table
The specifier scan loop is plainly visible in the disassembly: a counter of 23, a base address, and a stride of 6. Read the first byte of each of those 23 entries and they spell dsgzqQwcouxXfeEGin%pTSr, which is SQLite's fmtinfo[] table in order, byte for byte. A function that owns the format-specifier table is the printf implementation, whatever it is called.
struct field offsets
The first argument is an sqlite3_str*. The offsets the function loads from are 0x10, 0x14, 0x18, 0x1c and 0x1d, the last two as bytes. That is exactly nAlloc, mxAlloc, nChar, accError and printfFlags, laid out after a pointer to the database handle and a pointer to the text buffer.

One function, in one binary we built ourselves, argued by an analyst with every command printed. Violet RE does not do this part for you. What it does is the part above: once a name is proposed, the gate decides whether it survives, and the report says which gate rejected the ones that did not.

.findings

Check your own builds for known vulnerable patterns.

Shipped code is often code nobody on the team has read. Violet RE checks the recovered source for weakness types with a long public record: command and SQL injection, path traversal, template injection, unsafe deserialisation, server-side request forgery, hard-coded credentials, disabled TLS checks, unbounded string copies, and Android components exported without protection. No source code needed. Rule-based checks miss things.

A finding is a candidate, not a verdict. It names the weakness type (CWE), severity and confidence, the conditions required to reach it, the impact, the remediation, and what the analysis could not verify.

your releases
Check a build before it ships, from the binary rather than the repository.
mobile apps
APK, AAB and IPA. Android packages also get component export, WebView and cleartext traffic checks.
supplier software
Review a vendor binary you are authorised to assess, when there is no source to read.
violet_source/libexample/device.c recovered source
void load_device_name(const char *src)
{
    char name[64];
    strcpy(name, src);
    set_label(name);
}

int apply_config(const struct config *cfg)
{
    if (cfg->device_name == NULL)
        return -1;
    load_device_name(cfg->device_name);
    return 0;
}

device.c -- 14 lines shown

report/findings/F-0007 illustrative finding
title        Unbounded C string copy
             requires a proven
             destination bound
cwe          CWE-120
severity     HIGH (CVSS 8.1)
confidence   PROBABLE
component    libexample.so,
             load_device_name
cve_ids      none claimed
conditions   copy is in a reachable
             build; src can exceed
             the destination
impact       memory past name may
             be overwritten
limitations  text-pattern rule;
             destination bound,
             callers, reachability
             not established;
             target not executed
remediation  bound the copy to
             sizeof(name)
evidence     sha256:0000...0000
             (placeholder)

F-0007 -- a candidate, not a verdict

rule
strcpy call (text pattern)
confidence
Probable
target executed
No

Illustrative only, not a customer result. The library, function and hash are placeholders. The finding is marked probable because a text-pattern rule matched strcpy. Destination size, callers and reachability were not established. It says so, rather than rounding up.

.corpus

Where the vulnerability data comes from, and what it is allowed to do.

Three public sources feed it: the CVE List V5 records maintained by the CVE Program, the enrichment NVD publishes on top of them, and the CISA Known Exploited Vulnerabilities catalogue. Every record keeps the source it arrived from and the date it was read. None of it is ours, and none of it is private.

Its job in an analysis is retrieval. Records and past fixes that resemble the code in front of the analyser are pulled in to steer where it looks, and that is the whole of the mechanism. Retrieved context carries no confidence effect: it cannot raise a finding, confirm one, or add a line to a report on its own. The counts below are an inventory of what is held. They are not a coverage claim, and your binary is not compared against them.

inventory as at 20 September 2026 -- counts move daily

field count what the field actually records
vulnerability_records 353,019 Public vulnerability records ingested from CVE List V5, NVD and CISA KEV, each keeping its source. Public data: anyone can hold the same set. The number is here to be exact about what is stored, not to suggest a build gets checked against 353,019 vulnerabilities.
kev 1,715 Records that appear in the CISA Known Exploited Vulnerabilities catalogue, carried through as a flag on the record.
repository_urls 64,161 Records that carry a GitHub or GitLab URL among their references. The field is derived by scanning every reference URL for a github.com or gitlab.com path. It is metadata and nothing more: it does not prove the repository exists, does not establish that it is the right repository, and does not authorise fetching it.
patch_urls 146,726 Records that carry a reference NVD tagged as a patch or as a vendor advisory. Sampling puts the commit-URL share at roughly 5 to 21 per cent; the rest is dominated by vendor advisory pages. It is a count of references carrying a tag, not a count of fixes anyone can read, and it is not presented as one.
public_poc_status 64,882 Records with a public proof-of-concept reference. The URL is held as metadata. Exploit code is never downloaded and never run.
patch_candidates 24,469 Commits nominated by a record's own references as the fix for it, queued for checking. A nomination is a claim made by a reference, not a fact.
state = VERIFIED 226 Candidates that have passed that checking. The other 24,243 have not, and are not treated as though they had.
patch_pairs 2,064 Before and after pairs of the changed code, extracted from commits nominated in advisory references. Extraction is read-only: the fix is never checked out and never built. Being a pair says nothing about whether the nomination was ever checked: 986 come from a candidate that passed checking and 1,078 do not.
training_safe 590 Pairs that cleared the gate deciding whether a pair may be used at all: relevance policy ADVISORY_PATCH_RELEVANCE_V1, state ADMITTED, confidence VERIFIED or HIGH. The remaining 1,474 are quarantined, and a quarantined pair does nothing. Clearing the gate is permission to study a pair, not evidence about anyone's build.
trusted_patterns 0 Aggregate patterns over those pairs promoted to the trusted set: none. 257 are quarantined and awaiting review. No pattern from this table is in use in any analysis today.
guides, never concludes
Retrieval steers where the analyser looks. It carries no confidence effect, so a resemblance to a past vulnerability can never create a finding, raise its severity or confirm it.
no advisory matching
Jobs submitted through the website run a bounded static pass with advisory queries switched off in the job type itself. No CVE identifier and no advisory match reaches a customer report, because the customer manifest has no field to put one in.
read, never fetch
Repository URLs, patch references and proof-of-concept references are stored as metadata. Nothing in the table is cloned or downloaded while your job runs, and exploit code is never downloaded or run at all.
four gates, not one
Nominating a fix commit, verifying it, extracting a pair and promoting an aggregate pattern are four separate steps with four separate gates. The counts above show how many records survive each one, and the last gate has let nothing through.
the other patterns
A second and separate thing is also called a pattern: one promoted from a confirmed finding on a target rather than from the pairs above. A pattern from a confirmed finding is promoted only after the same weakness is confirmed independently in separate targets. Rerunning one target cannot confirm it. Free-tier patterns enter only under the data condition set out below, and paid work never does.
no uplift claimed
No gain in detection is claimed until one is measured on held-out cases. The model used to retrieve similar code is pretrained and pinned rather than trained here, and no uplift from any of this has been measured.

Your binary is not matched against every CVE in this inventory. Holding a record about a vulnerability is not the ability to find it in your binary, and the reverse holds too: the checks can match code that no record describes. Zero matches do not mean zero vulnerabilities.

The worked SQLite teardown in the analysis writeups takes a published CVE this service would not find, and says exactly why.

.report

What you get back.

  1. Vulnerability findings, with their limits

    Weakness class (CWE), severity, a confidence level, the affected component, the conditions required to reach it, an impact assessment, remediation guidance and evidence hashes. Each finding also states what the analysis could not verify.

  2. Both source files ship

    Two files per unit: the raw decompiler output and the Violet reconstruction. Neither is the developer's original source code. Both are readable, and transformation records and rejection logs ship alongside them.

  3. Nothing is renamed quietly

    The report counts accepted proposals and rejected proposals, and names the gate that rejected each one.

  4. Browser, PDF, ZIP

    A browser report for triage, a PDF for people who were not in the room, and a content-addressed ZIP whose contents are fixed by contract: the report, the manifest, and the paired source trees. Nothing else is permitted inside it.

.scope

What you will be able to send.

formatleading bytesascii
PE4d 5aMZ
ELF7f 45 4c 46.ELF
Mach-Ocf fa ed fe....
WebAssembly00 61 73 6d.asm
APK50 4b 03 04PK..
AAB50 4b 03 04PK..
IPA50 4b 03 04PK..
Archivescontainer dependent

Format and architecture detection is automatic. Supported extension labels are not guarantees that a particular target can be recovered, and the report says so when coverage is partial.

  • not a sandbox Targets are never executed on the public tier. No dynamic analysis, no network callbacks, no sandbox escape surface. Public work is bounded and static.
  • not an exploit generator Nothing is run, so nothing is proven exploitable. Findings state the conditions required to reach a weakness, and confirmation stays with you.
  • not a name generator The deobfuscation engine is over 7,000 lines of dedicated code: bytecode-equivalence gates for Python, Tree-sitter structural validation for C, C++ and Java, and per-proposal accept and reject tracking.

.release

When you can use it.

expected release

Spring 2027

Violet RE is staged and closed. When it opens, this page is replaced by the product.

These are the free-tier limits as designed today, not an open offer:

  • two analyses per UTC calendar month, up to 50 MB per target.
  • severity counts only on the free tier: critical, high, medium, low, info, plus the total number of findings.
  • reports kept 24 hours on the free tier. Paid plans keep them longer.
  • no card required for the free tier.
  • data condition Free use carries a data condition with no opt-out: independently validated, de-identified, generalisable structural patterns may be used in Violet's pattern library. Raw binaries, recovered source, source fragments, credentials, filenames, identifiers, report prose and customer-specific embeddings are excluded. Paid plans are isolated by default, and nothing from them enters general learning.

Prices, paid-plan allowances and the commercial terms are published at launch. Anything quoted before then is provisional.