Files
2026-04-30 21:31:32 +02:00

22 KiB
Raw Permalink Blame History

Concerns & Technical Debt

Analysis Date: 2026-04-30


Security Issues

[HIGH] Database credentials committed to version control

  • File: application/config/database.php
  • Detail: Production MySQL username (host420804_db) and plaintext password (VanMzwjUn85ySRyR) are hardcoded and committed to git.
  • Impact: Anyone with access to the repository has full database access. This is especially dangerous given the repo is on a shared hosting environment.
  • Fix: Move credentials to a .env file or server-level environment variables. Add application/config/database.php to .gitignore and use a database.php.example as template.

[HIGH] FTP credentials committed to version control

  • File: .vscode/ftp-kr.json
  • Detail: Production FTP credentials are committed — host host420804.hostido.net.pl, username www@centrumcopy.com.pl, and plaintext password (JHycfrHnyEAYsJHtR26C). Protocol is plain FTP (not SFTP).
  • Impact: Full read/write access to the production server's public_html for anyone with repo access.
  • Fix: Add .vscode/ftp-kr.json to .gitignore. Switch from FTP to SFTP. Store credentials outside the repository.

[HIGH] Unprotected install controller accessible in production

  • File: application/controllers/install.php
  • Detail: The install route is publicly routable ($config['install/*(.*)'] = 'install/$1' in application/config/routes.php). The controller can create users and insert database records. No authentication check. Visiting /install/init in a browser would recreate seed data, including writing admin users.
  • Impact: Any visitor can trigger /install/user/admin which resets admin credentials to admin/admin.
  • Fix: Delete or disable the install controller in production. At minimum wrap every method with an IP whitelist or a production check using IN_PRODUCTION.

[HIGH] Force-login backdoor controller

  • File: application/controllers/admin/force.php
  • Detail: Force_Controller::login() logs in as user ID 1 with no password check whatsoever, then sets the admin session. It is reachable at /admin/force/login via the catch-all route $config['admin/(.*)'] = 'admin/$1'.
  • Impact: Any visitor can visit /admin/force/login and immediately gain full admin access without credentials.
  • Fix: Delete this file immediately. It appears to be a developer debug shortcut left in the codebase.

[HIGH] Debug output (print_r($_POST)) in the login controller

  • File: application/controllers/admin/user.php, line 29
  • Detail: print_r($_POST) is called on every POST to the login form. This outputs all submitted POST data (including username and password) directly to the browser response.
  • Impact: Credentials are exposed in the HTTP response body. May also interfere with redirects.
  • Fix: Remove this line immediately.

[HIGH] Unescaped HTML output of page content in front-end views

  • Files: application/views/front/page_show.php (line 5), application/views/front/page_contact.php (line 5), application/views/default_layout.php (lines 73, 75)
  • Detail: $page->content, $page->header, $szybki_kontakt->content, and $szybki_kontakt->header are echoed raw with no escaping. Admin-saved HTML content is intentional (TinyMCE WYSIWYG), but if the admin account is compromised, an attacker could inject arbitrary JavaScript.
  • Impact: Stored XSS is possible through the admin panel if admin credentials are stolen.
  • Fix: Accept risk intentionally for trusted admin HTML content, but enforce strong auth (see CSRF and password hashing concerns). Document this explicitly.

[HIGH] No CSRF protection on any form

  • Files: All forms — admin_login.php, admin/page_edit.php, admin/password.php
  • Detail: Zero CSRF tokens are generated or validated on any POST form. Kohana 2.x includes no built-in CSRF protection. The forms rely solely on JavaScript-side validation, which is easily bypassed.
  • Impact: Any site can submit a form on behalf of a logged-in admin, changing page content or admin credentials.
  • Fix: Generate a per-session CSRF token in the base controllers and validate it on every POST.

[HIGH] Weak password hashing (SHA-1 with weak salt)

  • Files: application/controllers/admin/user.php (lines 33, 93, 97), application/controllers/install.php (lines 29, 36, 87, 93)
  • Detail: Passwords are hashed using sha1($salt . $password). The salt is generated as md5(rand(100000,999999) . $username . $email) — a low-entropy 6-digit random number seeded with predictable data. SHA-1 is cryptographically broken for password storage.
  • Impact: If the database is breached, passwords are easily crackable via rainbow tables or brute force.
  • Fix: Migrate to password_hash() / password_verify() with PASSWORD_BCRYPT or PASSWORD_ARGON2ID.

[MEDIUM] No rate limiting or lockout on the login endpoint

  • File: application/controllers/admin/user.php
  • Detail: The login form has no brute-force protection. There is no account lockout, CAPTCHA, or IP-based rate limiting after repeated failures. The last_failed timestamp is recorded but never acted upon.
  • Impact: Automated brute-force attacks against the admin login are unimpeded.
  • Fix: Add lockout logic after N failures within a time window, or integrate a CAPTCHA (Kohana has a Captcha library available).

[MEDIUM] Session ID never regenerated after login

  • File: application/config/session.php (line 43: 'regenerate' => 0), application/controllers/admin/user.php
  • Detail: session.regenerate is set to 0 (disabled). No manual session ID regeneration occurs on successful login. This allows session fixation attacks.
  • Fix: Call session_regenerate_id(true) immediately after successful login, or set 'regenerate' => 1.

[MEDIUM] Cookies are not HttpOnly

  • File: application/config/cookie.php (line 28: 'httponly' => FALSE)
  • Detail: Session cookies are accessible via JavaScript. Combined with any XSS vector, this enables session hijacking.
  • Fix: Set 'httponly' => TRUE.

[MEDIUM] Cookies are not Secure (no HTTPS enforcement)

  • File: application/config/cookie.php (line 23: 'secure' => FALSE), .htaccess
  • Detail: No HTTPS redirect is configured in .htaccess. Cookies are sent over plain HTTP. Google Maps API is loaded over HTTP (http://maps.google.com/...).
  • Fix: Add HTTPS redirect to .htaccess. Set cookie 'secure' => TRUE. Use https:// for external resources.

[MEDIUM] Google Maps v2 API key committed to repository

  • File: application/config/gmaps.php
  • Detail: A Google Maps API v2 key is hardcoded and committed. Google Maps v2 has been deprecated and shut down for years.
  • Fix: Remove the key. Migrate to Google Maps v3 (which uses domain restriction, not a key in the same way), or use an alternative mapping service.

[LOW] IN_PRODUCTION flag is false in the committed index.php

  • File: index.php (line 16: define('IN_PRODUCTION', false))
  • Detail: The production flag is hardcoded as false. This means Google Analytics is never included on the live site (guarded by IN_PRODUCTION). It also suggests dev and production use the same code file with no environment separation.
  • Fix: Use an environment variable or server-detected value to set this flag per environment.

Technical Debt

[HIGH] filter_var() emulation with security bypass

  • File: index.php (lines 6880)
  • Detail: If the PHP filter extension is not installed, filter_var() is replaced with a stub that always returns true, meaning all IP/URL validation silently passes without actually validating anything.
  • Impact: If running on a server without the filter extension, all input validation using filter_var is bypassed.
  • Fix: Require the filter extension explicitly in server requirements. Remove the stub.

[HIGH] Deprecated mysql_* functions used in system database driver

  • File: system/libraries/drivers/Database/Mysql.php
  • Detail: The Mysql driver uses mysql_connect(), mysql_query(), mysql_close(), etc. These functions were removed in PHP 7.0. The application is configured to use the mysqli driver (application/config/database.php), but the old Mysql.php driver still exists and would fail completely if the config were changed.
  • Impact: The old driver is dead code but signals the PHP version constraint this codebase was designed for.
  • Fix: Confirm mysqli driver is always used. Delete system/libraries/drivers/Database/Mysql.php or mark it clearly as unsupported.

[HIGH] Commented-out dead code throughout controllers

  • Files: application/controllers/admin/user.php (lines 810, 2930, 46, 63), application/controllers/base_admin.php (lines 13, 31, 4041), application/controllers/base_front.php (lines 1217, 4043)
  • Detail: Large blocks of commented-out functionality exist: disabled profiler, disabled cookie-based redirect, disabled homepage layout, disabled __destruct rendering. These represent abandoned design decisions.
  • Fix: Remove commented-out code. Use git history if rollback is ever needed.

[MEDIUM] stara/ directory — entire old website committed to repository

  • File: stara/ directory
  • Detail: An old version of the website (index.htm, Flash files, old HTM pages, images) is committed to the repository root and likely deployed to production alongside the current application.
  • Impact: Old pages may be publicly accessible. Increases repository size. Potential security exposure if old files have vulnerabilities.
  • Fix: Remove stara/ from the repository. If archival is needed, move it to a separate repository or offline storage.

[MEDIUM] Google Maps v2 integration (defunct API)

  • Files: application/config/gmaps.php, application/controllers/front/page.php, modules/gmaps/
  • Detail: The entire gmaps module integrates Google Maps JavaScript API v2, which was shut down in 2013. The map on the contact page will not render.
  • Fix: Rewrite the contact page map using Google Maps v3 or an alternative (e.g., Leaflet with OpenStreetMap). Remove the gmaps module.

[MEDIUM] Adobe Flash integration

  • Files: flash/centrumcopy.swf, flash/expressInstall.swf, application/views/default_layout.php (lines 4446, 94102)
  • Detail: Adobe Flash Player support was dropped by all browsers at end of 2020. The Flash banner on the homepage cannot be displayed.
  • Fix: Remove the Flash files and swfobject integration from the layout. Replace with a static image or CSS/HTML5 animation.

[MEDIUM] Menu and navigation structure hardcoded in two separate places

  • Files: application/config/application.php ($config['menu_nav']), application/views/admin_layout.php (admin sidebar links)
  • Detail: The navigation menu is defined once in config (rendered for front-end) and a parallel, nearly duplicate list exists hardcoded in the admin layout view. Adding a new page requires editing both files.
  • Fix: Drive the admin sidebar from the same data source as the front-end menu config.

[LOW] TinyMCE 3.x (ancient WYSIWYG editor)

  • File: js/tiny_mce/
  • Detail: TinyMCE 3.x is bundled. TinyMCE is now at version 7. Version 3 is no longer maintained and may have known XSS vulnerabilities in the editor itself.
  • Fix: Upgrade to TinyMCE 6/7 or replace with a modern editor (e.g., Quill, ProseMirror).

[LOW] jQuery and jQuery UI versions are unversioned/unknown

  • Files: js/jquery.min.js, js/jquery-ui.min.js
  • Detail: No version number is visible in the filenames. Given the use of IE7 polyfills and Flash, these are likely very old versions.
  • Fix: Replace with a pinned, modern version (jQuery 3.x). Consider migrating away from jQuery UI entirely.

[LOW] IE7 polyfill scripts loaded from external CDN via HTTP

  • Files: application/views/default_layout.php (line 15), application/views/admin_layout.php (line 10), application/views/admin_login.php (line 10)
  • Detail: ie7-js.googlecode.com is loaded as an external HTTP script. Google Code shut down in 2016; this URL returns a 404 or is hijacked. IE7 support is irrelevant in 2024+.
  • Fix: Remove all IE7 conditional comments and scripts.

Performance Concerns

[MEDIUM] N+1 query risk on every page load — szybki-kontakt page

  • File: application/controllers/base_front.php (line 31)
  • Detail: Every page load on the front-end executes ORM::factory('page')->where('name', 'szybki-kontakt')->find() in the base controller constructor. This is a database query run on every single front-end request, even pages that don't display the sidebar contact snippet.
  • Fix: Cache this result in a static variable or application-level cache. Consider storing it in config if the content rarely changes.

[MEDIUM] Database query benchmarking enabled in production config

  • File: application/config/database.php (line 28: 'benchmark' => TRUE)
  • Detail: Query benchmarking adds overhead to every database call.
  • Fix: Set 'benchmark' => FALSE in production, or use the IN_PRODUCTION flag to switch configs.

[LOW] No HTTP caching headers configured

  • Files: .htaccess, application/config/
  • Detail: No Cache-Control, Expires, or ETags are configured for static assets (CSS, JS, images). The .htaccess has no asset caching rules.
  • Fix: Add browser caching rules in .htaccess for static file extensions.

[LOW] All front-end JavaScript loaded synchronously in <head>

  • File: application/views/default_layout.php (lines 1830)
  • Detail: 7+ JS files are loaded with blocking <script> tags in the document <head>, including the defunct Flash embed script.
  • Fix: Move scripts to bottom of <body> or use defer/async attributes.

Dependency Risks

[HIGH] Kohana 2.3.x — end-of-life framework

  • Files: system/ directory
  • Detail: The application uses Kohana 2.3 (evidenced by the $Id: index.php 4134 2009-03-28... comment and Kohana framework version markers). Kohana has been end-of-life since approximately 2016. No security patches, no community support.
  • Impact: Any framework-level vulnerability will never be patched. The framework depends on deprecated PHP 5.2+ APIs.
  • Fix: Plan a migration to a maintained framework (Laravel, Symfony, or even Kohana 3.x). This is a major long-term effort.

[HIGH] PHP 5.2 minimum — framework requirement

  • File: index.php (line 45: version_compare(PHP_VERSION, '5.2', '<'))
  • Detail: The codebase targets PHP 5.2. PHP 5.x has been end-of-life since December 2018. Modern PHP (8.x) has breaking changes for deprecated functions used in this codebase (especially mysql_* functions removed in PHP 7).
  • Impact: If the server is upgraded to PHP 8.x, the application will break. If the server remains on PHP 5.x, it runs on an unsupported, vulnerability-riddled runtime.
  • Fix: Verify the current PHP version in production. Audit for PHP 7/8 incompatibilities and fix them before any server upgrade.

[HIGH] SwiftMailer v3 (abandoned)

  • File: system/vendor/swift/
  • Detail: SwiftMailer v3 is bundled in the framework vendor directory. SwiftMailer was abandoned and superseded by Symfony Mailer. Version 3 is extremely old.
  • Fix: If email sending is ever needed, replace with PHPMailer or Symfony Mailer.

[MEDIUM] Google Maps API v2 (shut down 2013)

  • See Technical Debt section above. The map simply does not work.

[MEDIUM] Adobe Flash (deprecated end of 2020)

  • See Technical Debt section above.

Maintainability

[HIGH] No database schema documentation

  • Files: .paul/codebase/ (referenced in CLAUDE.md but db_schema.md does not exist), no migration files anywhere
  • Detail: There is no schema file, no migration system, and no documentation of the database structure. The only way to know the schema is to connect to the production database.
  • Fix: Reverse-engineer the current schema and create .paul/codebase/db_schema.md. Consider introducing a migration tool (e.g., Phinx) for future schema changes.

[HIGH] No .gitignore for sensitive or generated files

  • Files: Project root
  • Detail: No .gitignore exists (or it is not present in the working tree). As a result, application/config/database.php (with production credentials), .vscode/ftp-kr.json (with FTP credentials), application/cache/ (generated cache files), and application/logs/ (log files) are all committed.
  • Fix: Create a .gitignore immediately. At minimum exclude: application/config/database.php, .vscode/ftp-kr.json, application/cache/*, application/logs/*, uploads/.

[MEDIUM] Error from log reveals a known PHP compatibility bug

  • File: application/logs/2024-05-18.log.php
  • Detail: Log entry: Creating default object from empty value in application/controllers/admin/user.php at line 10. This is caused by the commented-out $this->message->password_success = ... code — $this->message is never initialized as an object, so assigning to it on a modern PHP version throws an error. The code in User_Controller::password() calls $this->message->password_success (line 108) which would also fail.
  • Fix: Initialize $this->message as new stdClass() in the Base_Admin_Controller constructor, or replace with an array.

[MEDIUM] Duplicated forward() method in both base controllers

  • Files: application/controllers/base_admin.php (lines 6886), application/controllers/base_front.php (lines 6785)
  • Detail: The forward() method is identical in both base controllers. Any change must be made in two places.
  • Fix: Extract to a shared parent controller or a trait (PHP 5.4+).

[MEDIUM] Duplicated error404() method in both base controllers

  • Files: application/controllers/base_admin.php (lines 5161), application/controllers/base_front.php (lines 5160)
  • Detail: Same issue as forward() — identical implementation in two classes.
  • Fix: Same resolution — extract to a shared parent.
  • Files: application/views/default_layout.php (line 84), application/views/admin_layout.php (line 104), application/views/admin_login.php (line 51)
  • Detail: All footer copyright notices show © 2010. The site appears abandoned from a maintenance perspective.
  • Fix: Use date('Y') dynamically or update to current year range.

[LOW] Inactive/unused models committed

  • Files: application/models/gallery.php, application/models/gallery_image.php, application/models/news.php
  • Detail: Models for gallery, gallery_image, and news exist but no corresponding controllers, routes, or views for these features are present (the gallery and news routes exist in routes.php but route to non-existent controllers front/gallery and front/news).
  • Impact: Visiting /galeria or /aktualnosci will produce a 404 or Kohana error.
  • Fix: Either implement these features or remove the dead models and routes.

Missing Practices

[HIGH] No test suite whatsoever

  • Detail: There are no test files anywhere. Kohana's unit_test module is commented out in application/config/config.php. There is no PHPUnit setup, no test directory, no test runner.
  • Impact: Any change to the codebase carries unknown risk. Regressions cannot be detected automatically.
  • Fix: At minimum, add PHPUnit and write smoke tests for the login flow and page rendering. The Kohana unit_test module can serve as a starting point.

[HIGH] No error tracking / monitoring

  • Detail: The only error tracking is file-based logging to application/logs/. There is no integration with Sentry, Bugsnag, Rollbar, or equivalent. Log files are PHP files (which is a Kohana convention to prevent direct web access, but is not a proper log management solution).
  • Fix: Integrate Sentry (free tier) for real-time error tracking.

[HIGH] No deployment procedure documented

  • File: CLAUDE.md
  • Detail: The CLAUDE.md explicitly notes (Uzupełnij procedurę deploy). The only deployment mechanism is an FTP auto-upload via VS Code extension. There is no deployment script, no CI/CD pipeline, no staging environment concept.
  • Fix: Document the deploy procedure. Consider a simple deployment script. Move away from FTP (use SFTP or SSH-based deployment).

[MEDIUM] No environment separation (dev vs production)

  • Detail: There is a single set of config files. IN_PRODUCTION = false is hardcoded. Database credentials are for production. Debug toolbar (application/config/debug_toolbar.php, auto_render => TRUE) is enabled and would render if the debug module were active.
  • Fix: Implement environment detection (e.g., via $_SERVER['HTTP_HOST'] or a server env var) and load environment-specific config overrides.

[MEDIUM] No HTTPS enforcement

  • Files: .htaccess, application/config/cookie.php
  • Detail: No redirect from HTTP to HTTPS exists in .htaccess. The site is likely accessible over plain HTTP, exposing session cookies and login credentials over the wire.
  • Fix: Add HTTPS redirect to .htaccess. Enable 'secure' => TRUE in cookie config after HTTPS is enforced.

[LOW] No Content Security Policy (CSP) headers

  • Detail: No CSP headers are set anywhere. Given the TinyMCE editor and Google Maps integration, a CSP would need to be permissive, but even a basic policy would reduce XSS risk.
  • Fix: Add Content-Security-Policy header in .htaccess or in the base controller output.

[LOW] Google Analytics configuration is empty

  • File: application/config/application.php (line 11: $config['google_analytics'] = '')
  • Detail: The Google Analytics tracking code is empty. The legacy GA v1 code in default_layout.php (lines 109118) uses the deprecated ga.js library, not gtag.js. Even if a tracking ID were provided, it would use an obsolete tracking method.
  • Fix: Either remove Google Analytics entirely or migrate to GA4 with gtag.js.

Concerns audit: 2026-04-30