The Roundcube Webmail suite
This report summarizes scanner evidence for roundcube/roundcubemail, a PHP project with 7,253 GitHub stars. SynthScan examined 193,917 lines of code across 967 source files, recording 130 pattern matches distributed across 8 syntactic categories. The legacy adjusted pattern signal is 0.8 (Low pattern signal); it is not an authorship estimate.
Use the findings to ask whether maintainers can explain intent, verify dependencies, simplify unnecessary scaffolding, and focus review effort. Risk Payload v1 adds ownership, supply-chain, over-engineering, and review-effort vectors when available. These are prompts for human verification, not probabilities, security findings, or measured maintenance costs.
Use each vector to guide manual verification of the underlying findings.
Payload schema: 1.0.0 · Engine: 2.0.0 · Scoring: heuristic-density-v1 · Scan date: 2026-10-31.
Can maintainers explain intent, assumptions, and trade-offs? 67 finding(s).
Are imports declared and package/API names verified? 63 finding(s).
Are wrappers, guards, and repeated structures necessary? 14 finding(s).
Which changes need focused human review? 130 finding(s).
This chart tracks the legacy adjusted pattern score across scan runs. Changes can reflect source changes, scan coverage, or detector/scoring versions; they do not measure AI adoption or prove that a team refactored code. Compare runs only when their scoring versions are compatible. The dashed line tracks the raw pattern-hit count.
Groups findings by configured severity weight. Severity is not a confidence estimate, security rating, or proof that a package is missing. Verify imports against the project's manifests and inspect each finding in its local design context.
This horizontal bar chart shows where configured pattern scores accumulate across directories. Treat the bars as locations to inspect, not as evidence of authorship or code quality. Use the file-level findings to decide whether a directory needs a focused ownership, dependency, complexity, or review check.
The scanner identified 130 distinct pattern matches across 8 syntactic categories. Each entry below represents a discrete location in the source code where the engine recorded a detector match to inspect in context. Expand any category row to inspect the individual file paths, line numbers, code snippets, and the lexical context (CODE, COMMENT, or STRING) in which each match was detected.
Reading the findings table: The Severity column indicates the configured finding weight (CRITICAL / HIGH / MEDIUM / LOW). The Context column identifies whether the match occurred inside executable code, an inline comment, or a string literal — legacy comment-context matches receive a ×1.5 score weight. The ⚡ bolt icon marks clustered matches: three or more patterns within a 10-line window, each receiving an additional ×1.5 density multiplier under the legacy scoring model.
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | plugins/jqueryui/js/jquery-ui.min.js | 6 | !function(t){"use strict";"function"==typeof define&&define.amd?define(["jquery"],t):t(jQuery)}(function(V){"use strict" | CODE |
| LOW | plugins/password/drivers/ximss.php | 55 | // <session id="A001" urlID="4815-vN2Txjkggy7gjHRD10jw" userName="user@example.com"/>\0 | COMMENT |
| LOW | …ns/example_addressbook/example_addressbook_backend.php | 34 | 'name' => 'John Doe', | CODE |
| LOW | plugins/additional_message_headers/composer.json | 10 | "email": "email@example.org", | CODE |
| LOW | plugins/markdown_editor/tests/Browser/ComposeTest.php | 91 | $browser->keys('#compose_to input', 'user@example.com'); | CODE |
| LOW | plugins/managesieve/managesieve.js | 955 | placeholder: $(field).attr('placeholder'), | CODE |
| LOW | …ugins/managesieve/lib/Roundcube/rcube_sieve_engine.php | 1785 | 'placeholder' => $this->plugin->gettext('headername'), | CODE |
| LOW | skins/elastic/ui.js | 780 | $(input).filter('.datepicker').attr('placeholder', format); | CODE |
| LOW | skins/elastic/ui.js | 1170 | .attr('placeholder', label.text()) | CODE |
| LOW | skins/elastic/ui.js | 2074 | placeholder = input.attr('placeholder'), | CODE |
| LOW | skins/elastic/ui.js | 2144 | input.attr('placeholder', e.type == 'blur' ? placeholder : ''); | CODE |
| LOW | tests/Framework/UserTest.php | 83 | $this->assertSame('test@example.org', $all[1]['email']); | CODE |
| LOW | tests/Framework/UserTest.php | 98 | $this->assertSame('test@example.org', $idents[1]['email_ascii']); | CODE |
| LOW | tests/Framework/UserTest.php | 136 | $this->assertSame('test@example.org', $idents[2]['email']); | CODE |
| LOW⚡ | tests/Framework/ContactsTest.php | 36 | $data = ['email' => '@example.org']; | CODE |
| LOW⚡ | tests/Framework/ContactsTest.php | 38 | $this->assertSame(['type' => 3, 'message' => 'Invalid email address: @example.org'], $contacts->get_error()); | CODE |
| LOW⚡ | tests/Framework/ContactsTest.php | 40 | $data = ['email' => 'test@test.com']; | CODE |
| LOW | tests/Framework/SmtpTest.php | 33 | 'From' => '"John Doe" <john@domain.tld>', | CODE |
| LOW | tests/Framework/MimeTest.php | 160 | 1 => ['name' => 'attacker@example.org', 'mailto' => 'admin@example.net', 'string' => '"attacker@example. | CODE |
| LOW⚡ | tests/Framework/AddressbookTest.php | 17 | $data = ['email' => 'test@test.com', 'other' => 'test']; | CODE |
| LOW⚡ | tests/Framework/AddressbookTest.php | 20 | $this->assertSame(['test@test.com'], $result); | CODE |
| LOW⚡ | tests/Framework/AddressbookTest.php | 22 | $data = ['email:home' => 'test@test.com', 'other' => 'test']; | CODE |
| LOW⚡ | tests/Framework/AddressbookTest.php | 25 | $this->assertSame(['test@test.com'], $result); | CODE |
| LOW⚡ | tests/Framework/AddressbookTest.php | 27 | $data = ['email:home' => 'test@test.com', 'other' => 'test']; | CODE |
| LOW⚡ | tests/Framework/AddressbookTest.php | 30 | $this->assertSame(['home' => ['test@test.com']], $result); | CODE |
| LOW | tests/Rcmail/SendmailTest.php | 99 | \rcmail_sendmail::extract_inline_images($message, 'test@test.com'); | CODE |
| LOW | tests/Rcmail/SendmailTest.php | 106 | \rcmail_sendmail::extract_inline_images($message, 'test@test.com'); | CODE |
| LOW | tests/Rcmail/OauthTest.php | 34 | 'name' => 'John Doe', | CODE |
| LOW | tests/Rcmail/OauthTest.php | 399 | 'name' => 'John Doe', | CODE |
| LOW | tests/Rcmail/OauthTest.php | 407 | 'user_name' => 'John Doe', | CODE |
| LOW | tests/Rcmail/OauthTest.php | 426 | 'name' => 'John Doe', | CODE |
| LOW | tests/Rcmail/OauthTest.php | 437 | $this->assertSame($answer, ['user_name' => 'John Doe']); | CODE |
| LOW | tests/Rcmail/OutputHtmlTest.php | 291 | $txt = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ' | CODE |
| LOW | tests/Rcmail/OutputHtmlTest.php | 291 | $txt = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ' | CODE |
| LOW | tests/Browser/README.md | 37 | $config['tests_username'] = 'roundcube.test@example.org'; | CODE |
| LOW | tests/Browser/Contacts/ExportTest.php | 33 | $this->assertSame('John Doe', $contacts[0]->displayname); | CODE |
| LOW | tests/Browser/Contacts/ExportTest.php | 60 | $this->assertSame('John Doe', $contacts[0]->displayname); | CODE |
| LOW | tests/Browser/Contacts/PrintTest.php | 49 | ->assertSeeIn('#contacttabs', 'johndoe@example.org'); | CODE |
| LOW⚡ | tests/Browser/data/data.sql | 2 | INSERT INTO contacts (user_id, changed, del, name, email, firstname, surname, vcard, words) VALUES (1, '2019-12-31 12:23 | CODE |
| LOW⚡ | tests/Browser/data/data.sql | 2 | INSERT INTO contacts (user_id, changed, del, name, email, firstname, surname, vcard, words) VALUES (1, '2019-12-31 12:23 | CODE |
| LOW⚡ | tests/Browser/data/data.sql | 7 | END:VCARD', ' john do johndo@example.org'); | CODE |
| LOW | tests/Actions/Settings/IdentitiesTest.php | 33 | $this->assertTrue(str_contains($result, 'test@example.org')); | CODE |
| LOW | tests/Actions/Settings/IdentityDeleteTest.php | 27 | $query = $db->query('SELECT * FROM `identities` WHERE `email` = ?', 'test@example.org'); | CODE |
| LOW | tests/Actions/Contacts/MailtoTest.php | 27 | $query = $db->query('SELECT `contact_id` FROM `contacts` WHERE `email` = ?', 'johndoe@example.org'); | CODE |
| LOW | tests/Actions/Contacts/Group_DelmembersTest.php | 100 | . "VALUES (2, '2019-12-31 12:23:33', 0, 'John Doe', 'johndoe@example.org', 'John', 'Doe', '', '')"); | CODE |
| LOW | tests/Actions/Contacts/Group_DelmembersTest.php | 100 | . "VALUES (2, '2019-12-31 12:23:33', 0, 'John Doe', 'johndoe@example.org', 'John', 'Doe', '', '')"); | CODE |
| LOW | tests/Actions/Contacts/Group_AddmembersTest.php | 99 | . "VALUES (2, '2019-12-31 12:23:33', 0, 'John Doe', 'johndoe@example.org', 'John', 'Doe', '', '')"); | CODE |
| LOW | tests/Actions/Contacts/Group_AddmembersTest.php | 99 | . "VALUES (2, '2019-12-31 12:23:33', 0, 'John Doe', 'johndoe@example.org', 'John', 'Doe', '', '')"); | CODE |
| LOW⚡ | tests/src/sql/contacts.sql | 9 | VALUES (1, '2019-12-31 12:23:33.523071-05', 0, 'John Doe', 'johndoe@example.org', 'John', 'Doe', 'BEGIN:VCARD | CODE |
| LOW⚡ | tests/src/sql/contacts.sql | 9 | VALUES (1, '2019-12-31 12:23:33.523071-05', 0, 'John Doe', 'johndoe@example.org', 'John', 'Doe', 'BEGIN:VCARD | CODE |
| LOW⚡ | tests/src/sql/contacts.sql | 15 | END:VCARD', ' john do acme johndo@example.org'); | CODE |
| LOW | tests/src/sql/identities.sql | 3 | INSERT INTO identities (user_id, name, standard, email, signature) VALUES (1, 'test', '0', 'test@example.org', 'sig'); | CODE |
| LOW | program/include/rcmail_output_html.php | 2441 | if (empty($attrib['placeholder'])) { | CODE |
| LOW | program/include/rcmail_output_html.php | 2442 | $attrib['placeholder'] = $this->app->gettext('searchplaceholder'); | CODE |
| LOW | program/actions/mail/show.php | 355 | if (!empty($attrib['placeholder'])) { | CODE |
| LOW | program/actions/mail/show.php | 356 | $placeholder = $rcmail->output->abs_url($attrib['placeholder'], true); | CODE |
| LOW⚡ | program/actions/contacts/index.php | 1292 | } elseif (!empty($attrib['placeholder'])) { | CODE |
| LOW⚡ | program/actions/contacts/index.php | 1293 | $photo_img = $rcmail->output->abs_url($attrib['placeholder'], true); | CODE |
| LOW⚡ | program/actions/contacts/index.php | 1301 | unset($attrib['placeholder']); | CODE |
| LOW | program/lib/Roundcube/html.php | 409 | 'placeholder', 'autofocus', 'pattern', 'oninput', | CODE |
| 2 more matches not shown… | ||||
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | config/defaults.inc.php | 21 | COMMENT | |
| LOW | config/defaults.inc.php | 41 | COMMENT | |
| LOW | config/defaults.inc.php | 61 | ]; | COMMENT |
| LOW | config/defaults.inc.php | 121 | COMMENT | |
| LOW | config/defaults.inc.php | 141 | // For example %n = mail.domain.tld, %t = domain.tld | COMMENT |
| LOW | config/defaults.inc.php | 161 | // 'verify_peer' => true, | COMMENT |
| LOW | config/defaults.inc.php | 181 | COMMENT | |
| LOW | config/defaults.inc.php | 221 | // Some servers return hidden folders (name starting with a dot) | COMMENT |
| LOW | config/defaults.inc.php | 261 | // ---------------------------------- | COMMENT |
| LOW | config/defaults.inc.php | 281 | // Note: To disable user authentication set smtp_user and smtp_pass to ''. | COMMENT |
| LOW | config/defaults.inc.php | 321 | // See https://php.net/manual/en/context.ssl.php | COMMENT |
| LOW | config/defaults.inc.php | 421 | // OpenIDC protocol to get a short-living password (claim) for the user to log into IMAP/SMTP. | COMMENT |
| LOW | config/defaults.inc.php | 441 | // $config['oauth_token_uri'] = "https://oauth2.googleapis.com/token"; | COMMENT |
| LOW | config/defaults.inc.php | 461 | // $config['oauth_identity_uri'] = "https://graph.microsoft.com/v1.0/me"; | COMMENT |
| LOW | config/defaults.inc.php | 481 | // Define any number of hosts in the form of hostname:port or unix:///path/to/socket.file | COMMENT |
| LOW | config/defaults.inc.php | 501 | // Unset fields will be set to the default values host=127.0.0.1, port=6379. | COMMENT |
| LOW | config/defaults.inc.php | 541 | // current skin folder. Remove the slash to point to a file in the Roundcube | COMMENT |
| LOW | config/defaults.inc.php | 601 | // Location of temporary saved files such as attachments and cache files | COMMENT |
| LOW | config/defaults.inc.php | 621 | // Allow browser-autocompletion on login form. | COMMENT |
| LOW | config/defaults.inc.php | 661 | // Session authentication cookie name. Default: 'roundcube_sessauth' | COMMENT |
| LOW | config/defaults.inc.php | 681 | $config['session_storage'] = 'db'; | COMMENT |
| LOW | config/defaults.inc.php | 701 | $config['x_frame_options'] = 'sameorigin'; | COMMENT |
| LOW | config/defaults.inc.php | 721 | // %d - domain (http hostname, $_SERVER['HTTP_HOST'] without the first part) | COMMENT |
| LOW | config/defaults.inc.php | 741 | // Password character set, to change the password for user | COMMENT |
| LOW | config/defaults.inc.php | 801 | // According to RFC2298, return receipt envelope sender address must be empty. | COMMENT |
| LOW | config/defaults.inc.php | 821 | // Mimetypes supported by the browser. | COMMENT |
| LOW | config/defaults.inc.php | 861 | // This can be set to a number defining token length. Default: 16. | COMMENT |
| LOW | config/defaults.inc.php | 881 | // It should be used as a last resort for tricky environments (e.g. with proxies). | COMMENT |
| LOW | config/defaults.inc.php | 961 | $config['date_long'] = 'Y-m-d H:i'; | COMMENT |
| LOW | config/defaults.inc.php | 1001 | // Set the spell checking engine. Possible values: | COMMENT |
| LOW | config/defaults.inc.php | 1061 | // will be used. This is set to false for backwards compatibility. | COMMENT |
| LOW | config/defaults.inc.php | 1081 | // This indicates which type of address book to use. Possible choices: | COMMENT |
| LOW | config/defaults.inc.php | 1101 | // uid=user@domain | COMMENT |
| LOW | config/defaults.inc.php | 1141 | 'search_bind_pw' => '', | COMMENT |
| LOW | config/defaults.inc.php | 1161 | // If writable is true then these fields need to be populated: | COMMENT |
| LOW | config/defaults.inc.php | 1281 | // If there's more than one address book, n parallel (async) requests will be created, | COMMENT |
| LOW | config/defaults.inc.php | 1301 | // Warning: These are field names not LDAP attributes (see 'fieldmap' setting)! | COMMENT |
| LOW | config/defaults.inc.php | 1321 | // Default: true (the built-in "Trusted senders" addressbook, source id = '2') | COMMENT |
| LOW | config/defaults.inc.php | 1381 | // 0 - never, | COMMENT |
| LOW | config/defaults.inc.php | 1441 | // If true all folders will be checked for recent messages | COMMENT |
| LOW | config/defaults.inc.php | 1461 | COMMENT | |
| LOW | config/defaults.inc.php | 1481 | $config['force_7bit'] = false; | COMMENT |
| LOW | config/defaults.inc.php | 1501 | // Directly delete messages in Junk instead of moving to Trash | COMMENT |
| LOW | plugins/jqueryui/js/jquery.minicolors.min.js | 1 | // | COMMENT |
| LOW | program/lib/Roundcube/rcube_result_thread.php | 581 | // For the following structure: THREAD (2)(3 6 (4 23)(44 7 96))((11)(12)) | COMMENT |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| HIGH | program/include/rcmail.php | 503 | // remove from list if not writeable as requested | COMMENT |
| HIGH | program/include/rcmail.php | 507 | // remove from list if hidden as requested | COMMENT |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | .php-cs-fixer-fully_qualified_strict_types.php | 251 | protected function createConfigurationDefinition(): FixerConfigurationResolverInterface | CODE |
| LOW | .php-cs-fixer-fully_qualified_strict_types.php | 543 | private function setupUsesFromDiscoveredSymbols(array &$uses, string $namespaceName): void | CODE |
| LOW | tests/Framework/LdapGenericTest.php | 12 | protected function markTestSkippedIfNetLdapPackageIsNotInstalled(): void | CODE |
| LOW | tests/MessageRendering/MarkdownTest.php | 32 | public function testPlaintextAndMarkdownContent() | CODE |
| LOW | tests/MessageRendering/MarkdownTest.php | 57 | public function testPlaintextWithMarkdownAttachment() | CODE |
| LOW | …ts/MessageRendering/EmailAdressSpoofingAttacksTest.php | 14 | public function testEmailAdressSpoofingAttacks() | CODE |
| LOW | tests/MessageRendering/MessageRenderingTestCase.php | 43 | protected function runAndGetHtmlOutputDomxpath(string $msgId): \DOMXPath | CODE |
| LOW | …sts/MessageRendering/SingleAttachedImageNoTextTest.php | 14 | public function testShowMultipartMixedSingleImageToo() | CODE |
| LOW | …sts/MessageRendering/SingleAttachedImageNoTextTest.php | 30 | public function testShowUnreferredToImagesWithContentId() | CODE |
| LOW | …sts/MessageRendering/SingleAttachedImageNoTextTest.php | 45 | public function testShowUnreferredToImagesWithContentIdInMultipartAlternative() | CODE |
| LOW | tests/Public/StaticTest.php | 247 | public function testRangeHeaderSuffixLargerThanFile(): void | CODE |
| LOW | tests/Public/StaticTest.php | 273 | public function testRangeHeaderFullFileViaRange(): void | CODE |
| LOW | tests/Public/StaticTest.php | 295 | public function testRangeHeaderFullFileViaRangeEndBiggerThanSize(): void | CODE |
| LOW | tests/Public/StaticTest.php | 415 | public function testContentLengthAccuracy($path): void | CODE |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| CRITICAL | plugins/jqueryui/js/jquery-ui.min.js | 6 | !function(t){"use strict";"function"==typeof define&&define.amd?define(["jquery"],t):t(jQuery)}(function(V){"use strict" | CODE |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW⚡ | tests/Rcmail/OauthTest.php | 624 | // Step 1: User somehow ends up with a login URL stored (shouldn't happen, but test it) | COMMENT |
| LOW⚡ | tests/Rcmail/OauthTest.php | 627 | // Step 2: unauthenticated hook should NOT store login URLs | COMMENT |
| LOW | program/include/rcmail.php | 364 | // we need to check if default is writeable, if not we | COMMENT |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW⚡ | tests/Rcmail/OauthTest.php | 624 | // Step 1: User somehow ends up with a login URL stored (shouldn't happen, but test it) | COMMENT |
| LOW⚡ | tests/Rcmail/OauthTest.php | 627 | // Step 2: unauthenticated hook should NOT store login URLs | COMMENT |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | .github/workflows/message_rendering.yml | 29 | # re-building what our compose-file contains we can just use it. | COMMENT |