[DBTech] DragonByte Security

[DBTech] DragonByte Security [Paid] 5.3.0

No permission to buy (€14.95)
DragonByte Tech updated [DBTech] DragonByte Security with a new update entry:

5.2.0 Beta 2

Update highlights​

!!! This version requires PHP 8.2 !!!

This version adds an important security update to one of the security features in the Security addon. I heard you like security in your security... That's still a current reference, right? 👴

Anyway, for Bad Behaviour's "Reverse Proxy" feature, you can now enter trusted reverse proxy addresses.

Speaking of Bad Behaviour, this update includes a patch for an issue in its detection class that...

Read the rest of this update entry...
 
Hi,

I'm seeing an unhandled exception from the Tor exit node update cron in DBTech Security. The error occurred on September 17, 2026 at 08:00:

Code:
GuzzleHttp\Exception\ConnectException:
[Security] Error fetching TOR exit nodes: cURL error 35: Recv failure: Connection reset by peer

Request:
Code:
https://check.torproject.org/torbulkexitlist?ip=techolay.net&port=443

Relevant stack trace:
Code:
#15 src/addons/DBTech/Security/Repository/TorRepository.php(37): GuzzleHttp\Client->get(...)
#16 src/addons/DBTech/Security/Cron/Security.php(50): DBTech\Security\Repository\TorRepository->updateNodes()
#17 src/XF/Job/Cron.php(41): DBTech\Security\Cron\Security::updateTorNodes(...)

Environment:
  • PHP 8.5.9
  • libcurl 8.18.0
  • OpenSSL 3.5.5
I tested the same endpoint directly from the server afterward. Both command-line curl and PHP's cURL extension can access it successfully.

Repeated PHP tests return:
Code:
HTTP=200
CURL=0
IP=116.202.120.181
Response size=19074 bytes

TLS 1.3 negotiation and certificate verification are also successful. Therefore, this appears to have been a temporary connection reset rather than a persistent connectivity, DNS, certificate, or cURL issue.

Would it make sense for TorRepository::updateNodes() to catch temporary Guzzle ConnectException/RequestException failures instead of allowing them to propagate as a XenForo server error?

Since the Tor exit list is an external service, it seems preferable to retain the existing list when an update fails and retry it on the next scheduled cron run.
 
Hi,

Would it make sense for TorRepository::updateNodes() to catch temporary Guzzle ConnectException/RequestException failures instead of allowing them to propagate as a XenForo server error?

Since the Tor exit list is an external service, it seems preferable to retain the existing list when an update fails and retry it on the next scheduled cron run.
The list is only deleted if a list is successfully fetched. The reason why it logs as an exception in the XenForo server log is that I want the ability to inspect such failures, in case the API ever goes down. You can never rely on the status code to accurately judge whether it's a temporary failure or a permanent one - a 500 doesn't mean it's down, and a 404 can simply mean the URL changed, etc.
 
DragonByte Tech updated [DBTech] DragonByte Security with a new update entry:

5.3.0

Update highlights​

This version adds the option to require a minimum password strength when changing the password, as well as fixing an issue where the checkmark icon would not appear even when the new password satisfied the rules.


Complete Change Log​

Feature: New option to set a minimum password strength, shown alongside the other password rules
Fix: The checkmark icon no longer disappears when a password rule is satisfied

Read the rest of this update entry...
 

Found a small hiccup in any situation where someone is upgrading from the older 5.1 to the latest 5.3 branch. There's two parts to this... one being the upgrade from an older branch with older log data and what appears to be an impact on any new data logged after version 5.2.0.

On an upgrade, five columns change from TEXT to narrow VARCHAR, there's nothing to shorten the old rows first. So, the upgrade process fails with the stack trace below. This can easily bypassed by dumping the log table if there's nothing important there, TRUNCATE xf_dbtech_security_bad_behavior.

The second part of this is that the addon can potentially fail to log any request whose method is over 8 characters or whose URI is over 2,048. Essentially, an attacker who knows about it can keep their requests out of the audit log.

The sample error from our test for first part:
Code:
XF\Db\Exception: xf_dbtech_security_bad_behavior: MySQL query error [1406]: Data too long for column 'request_method' at row 63945
src/XF/Db/AbstractStatement.php:225
Generated by: Unknown account
Oct 18, 2026 at 8:37 AM

Stack trace

ALTER TABLE `xf_dbtech_security_bad_behavior`
MODIFY COLUMN `id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
MODIFY COLUMN `ip` VARCHAR(45) NOT NULL,
MODIFY COLUMN `date` DATETIME NOT NULL DEFAULT '0000-00-00 00:00:00',
MODIFY COLUMN `request_method` VARCHAR(8) NOT NULL,
MODIFY COLUMN `request_uri` VARCHAR(2048) NOT NULL,
MODIFY COLUMN `server_protocol` VARCHAR(12) NOT NULL,
MODIFY COLUMN `http_headers` MEDIUMTEXT NOT NULL,
MODIFY COLUMN `user_agent` MEDIUMTEXT NOT NULL,
MODIFY COLUMN `request_entity` MEDIUMTEXT NOT NULL,
MODIFY COLUMN `key` VARCHAR(50) NOT NULL,
ADD `status_message` MEDIUMTEXT DEFAULT NULL,
ADD `support_key` VARCHAR(64) NOT NULL DEFAULT '',
ADD `bot_category` VARCHAR(32) NOT NULL DEFAULT '',
ADD `bot_verified` TINYINT UNSIGNED NOT NULL DEFAULT '0',
ADD `ja3` VARCHAR(64) NOT NULL DEFAULT '',
ADD `h2_hash` VARCHAR(16) NOT NULL DEFAULT '',
ADD `header_order_hash` VARCHAR(16) NOT NULL DEFAULT '',
ADD `asn` VARCHAR(32) NOT NULL DEFAULT '',
ADD `country` VARCHAR(2) NOT NULL DEFAULT '',
ADD `request_time_ms` INT UNSIGNED NOT NULL DEFAULT '0',
ADD `enforcement_action` VARCHAR(16) NOT NULL DEFAULT 'enforced',
ADD `original_code` VARCHAR(50) NOT NULL DEFAULT '',
ADD KEY `idx_ip` (`ip`),
ADD KEY `idx_date` (`date`),
ADD KEY `idx_bot` (`bot_category`, `bot_verified`),
ADD KEY `idx_enforcement` (`enforcement_action`, `date`),
ADD KEY `idx_request_method` (`request_method`)
------------

#0 src/XF/Db/Mysqli/Statement.php(207): XF\Db\AbstractStatement->getException('MySQL query err...', 1406, '22001')
#1 src/XF/Db/Mysqli/Statement.php(83): XF\Db\Mysqli\Statement->getException('MySQL query err...', 1406, '22001')
#2 src/XF/Db/AbstractAdapter.php(96): XF\Db\Mysqli\Statement->execute()
#3 src/XF/Db/Schema/AbstractDdl.php(158): XF\Db\AbstractAdapter->query('ALTER TABLE `xf...')
#4 src/XF/Db/SchemaManager.php(157): XF\Db\Schema\AbstractDdl->apply()
#5 src/addons/DBTech/Security/Setup.php(326): XF\Db\SchemaManager->alterTable('xf_dbtech_secur...', Object(Closure))
#6 src/addons/DBTech/Security/Install/Upgrade905999970Trait.php(50): DBTech\Security\Setup->applyTables()
#7 src/XF/AddOn/StepRunnerUpgradeTrait.php(124): DBTech\Security\Setup->upgrade905020011Step1(Array)
#8 src/XF/AddOn/StepRunnerUpgradeTrait.php(73): DBTech\Security\Setup->upgradeStepRunner(905020011, 1, Array, NULL)
#9 src/XF/Cli/Command/AddOnActionTrait.php(116): DBTech\Security\Setup->upgrade(Array)
#10 src/XF/Cli/Command/AddOnSubAction.php(79): XF\Cli\Command\AddOnSubAction->performAddOnAction(Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput), Object(XF\AddOn\AddOn), Object(XF\Phrase), 'upgrade')
#11 src/vendor/symfony/console/Command/Command.php(298): XF\Cli\Command\AddOnSubAction->execute(Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput))
#12 src/vendor/symfony/console/Application.php(1040): Symfony\Component\Console\Command\Command->run(Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput))
#13 src/vendor/symfony/console/Application.php(301): Symfony\Component\Console\Application->doRunCommand(Object(XF\Cli\Command\AddOnSubAction), Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput))
#14 src/vendor/symfony/console/Application.php(171): Symfony\Component\Console\Application->doRun(Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput))
#15 src/XF/Cli/Runner.php(115): Symfony\Component\Console\Application->run(Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput))
#16 cmd.php(17): XF\Cli\Runner->run()
#17 {main}

Summary:

Upgrade Path: (1)
5.1.x → 5.2.0 Alpha 1 or later (as directly seen on 5.1.4 → 5.3.0) > [upgrade905020011Step1 → applyTables()] > Upgrade stops with MySQL 1406; table left unchanged.

Upgrade Path: (2)
Older than 5.0.0 Beta 2 → 5.2.0 or later > upgrade905000032Step1 → applyTables() (uses the current table definitions) > Same failure, one step earlier.

New Install:
Fresh install of 5.2.0 or later > Install cleanly, but log values are lost at log time.
 
Last edited:
Back
Top Bottom