# Routrel Audit > Audit the Ktor server and the Exposed data layer behind one Kotlin service before it ships - which routes anyone can call, what a malformed request does, what the client sees when something fails, what blocks the threads serving calls, what runs in which transaction, what SQL the queries become - then fix them. The free check runs in the browser and uploads nothing: it lexes the pasted Kotlin (one or more files), rebuilds its brace structure, resolves every route's full path and the authenticate block around it (following Route extension functions to where routing mounts them), reads every installed plugin and JWT verifier, reads every Exposed transaction with the fun it is in, the thread it runs on and what it writes, and runs 22 deterministic checks drawn from Ktor and Exposed practice. The paid server audit rates auth, handlers, errors and threads; the paid data audit rates transactions, queries and setup; both confirm or dismiss every flag of their lane and give exact before/after edits per finding. The paid fix lane writes the whole fixed files and a changes list tied to the flags. The page checks every quote and line against the paste, applies every edit and file back into the paste and re-runs its checks, and calls out a reply that repeats a credential from the paste. App: https://routrel-audit.skillsafe.ai/ API tutorial: https://routrel-audit.skillsafe.ai/api.html ## Input - The code pasted into one box, each file introduced by a `// file: ` line; dropped files or a dropped source folder are joined that way automatically, the build file first. A paste with no file line is read as one file (Main.kt, or build.gradle.kts when it is a build script). - Nothing is compiled or run: every flag is a reading of the text, with the file and line it points at. Kotlin strings, string templates, raw strings, char literals, backtick names and nested comments are lexed out first, so a comment that says runBlocking is never a finding. - A route handler is a get/post/put/patch/delete/head/options call with a trailing lambda and no receiver. Its path joins every enclosing route("...") prefix; when it lives in a `fun Route.x()`, the page follows the call of x() to where it is mounted (up to five levels) and adds that place's prefixes and authenticate blocks. A Route function the paste never mounts keeps an unknown prefix and its auth is not judged. - Coroutine code is a suspend fun body, a route handler, a plugin callback that runs per call (validate, challenge, StatusPages exception/status) or a coroutine builder's lambda. A transaction { } lambda is blocking, a newSuspendedTransaction { } lambda is coroutine code. - The missing-plugin checks (KT-09, KT-10) run only when an Application module with install(...) calls is pasted and every configure...() function it calls is in the paste. What a function in another file does, application.conf values and the database's own indexes are outside the check (KV-00 says so); your tests stay the ground truth. ## Flags the free check raises Server (the server audit and the fix lane): - KT-01 (high): runBlocking or Thread.sleep in a route handler, a suspend fun or other coroutine code; one flag per handler or fun. - KT-02 (medium): POST, PUT, PATCH or DELETE routes that are mounted, not inside any authenticate block (declared or at the mount), when the paste uses authentication; login, register, token, webhook and health paths are exempt. One flag per Route function. - KT-03 (high with allowCredentials = true, else medium): install(CORS) with anyHost(). - KT-04 (medium): a StatusPages exception handler whose response uses the exception (cause.message, toString, a template of it); logging it is fine. - KT-05 (medium): a jwt provider whose verifier is built with neither withAudience nor withIssuer (a verifier built outside the paste is unknown, not flagged). - KT-06 (medium): !! on call.parameters[...], queryParameters, headers, cookies or principal<...>(). - KT-07 (low): a request parameter passed straight to toInt/toLong/toDouble or UUID.fromString, when no StatusPages handler maps IllegalArgumentException (or NumberFormatException) to a response. - KT-08 (medium): call.respond inside an if (braced or not) with no return and no else, followed by another call.respond in the same block. - KT-09 (medium): a route receives a class with call.receive() and no ContentNegotiation is installed. - KT-10 (low): no StatusPages installed. Data (the data audit and the fix lane): - EX-01 (medium): transaction { } run from coroutine code, or a plain fun whose transaction { } is called from coroutine code (a handler), unless the call runs inside withContext(Dispatchers.IO). - EX-02 (high): exec, prepareStatement, executeQuery or executeUpdate whose SQL string has a template ($x, ${x}) or is concatenated with a value; table-name templates are exempt. - EX-03 (medium): like/notLike/ilike with a "%...%" pattern built from a template of a value whose name does not say it was escaped. - EX-04 (medium): a fun that opens two or more transactions, one of which writes; or a non-handler fun that calls two or more pasted funs that each open their own transaction, one of which writes. - EX-05 (medium): a fun whose declared return type names a DAO entity class and whose body runs a transaction. - EX-06 (medium for a query or a transaction per item, low for inserts only): selectAll/select/find/findById/count or insert/new, or a whole transaction, inside a for/while loop or a forEach/map/... lambda. - EX-07 (medium): Database.connect with a url argument and no DataSource (H2 in-memory and test files exempt). - EX-08 (medium when Flyway also migrates, else low): SchemaUtils.create or createMissingTablesAndColumns outside tests. - EX-09 (high): Table.update { } with no where argument - it updates every row. - EX-10 (low): selectAll()/select()/find()/all() chains that end in single() or first(). Both: KV-01 (medium) a literal credential - a secret-named val or argument, an Algorithm.HMAC256("...") key, a Bearer header, a password in a JDBC URL; KV-00 (info) context - counts, versions, what is outside the check. ## Free extras - Every route with its full path, the fun it is declared in, its authenticate providers and the types it receives; every plugin (CORS hosts and credentials, JWT audience and issuer); every Exposed transaction with its kind, thread, writes and queries; every table and entity. - Put any audit finding (or all of them, or the fixed files) back into the paste and re-run the check; undo puts the original back. - Exports: the check as Markdown, the flags as CSV, the edited or fixed code, the findings or changes as CSV, the whole result as JSON. ## Paid lanes (the `task` field) - `server` and `data`: `{task, verdict: blocked|needs_work|ready, headline, system, areas: [{area, status: sound|fragile|broken, note}], findings: [{id, flags, file, line, severity, area, title, evidence, why, edits: [{before, after}]}], flag_answers: [{flag, status: confirmed|dismissed, reason}], plan, questions, summary}`. Server areas: auth, handlers, errors, threads. Data areas: transactions, queries, setup. `before` is an exact slice of the file, applied in order. - `fix`: `{task, verdict: fixed|partial, headline, files: [{path, content}], changes: [{file, function, flags, change, why}], verify, open: [{item, flags, reason}], questions, summary}`. `content` is the whole file; every fun keeps its name, and a public one its signature and suspend or not. - Run input: `{task, code, facts, note?, audit_handoff?, retry_note?}` - all strings; `facts` is the page's analysis as a JSON string, cut for the lane (the server audit gets the server flags, the data audit the data flags, the fix lane all of them). Either audit hands its findings to the fix lane with every edit applied to `code`; the server audit can also hand its edited code to the data audit. - Model: gpt-terra, 10% publisher markup. A run needs a signed-in account; the reservation shown before a run is a hold, and only what the run uses is charged. ## Sources - kotlin-ktor-patterns by Affaan Mustafa, affaan-m/everything-claude-code (github.com/affaan-m/everything-claude-code, skills/kotlin-ktor-patterns), MIT - https://skillsafe.ai/skill/@affaan-m/kotlin-ktor-patterns - kotlin-exposed-patterns by Affaan Mustafa, affaan-m/everything-claude-code (github.com/affaan-m/everything-claude-code, skills/kotlin-exposed-patterns), MIT - https://skillsafe.ai/skill/@affaan-m/kotlin-exposed-patterns - The checks and the reconciliation are original to this app. Ktor, Exposed and Kotlin are JetBrains projects; Routrel Audit is an independent tool, not affiliated with or endorsed by JetBrains or the Kotlin Foundation.