22 KiB
22 KiB
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
.envfile or server-level environment variables. Addapplication/config/database.phpto.gitignoreand use adatabase.php.exampleas template.
[HIGH] FTP credentials committed to version control
- File:
.vscode/ftp-kr.json - Detail: Production FTP credentials are committed — host
host420804.hostido.net.pl, usernamewww@centrumcopy.com.pl, and plaintext password (JHycfrHnyEAYsJHtR26C). Protocol is plain FTP (not SFTP). - Impact: Full read/write access to the production server's
public_htmlfor anyone with repo access. - Fix: Add
.vscode/ftp-kr.jsonto.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
installroute is publicly routable ($config['install/*(.*)'] = 'install/$1'inapplication/config/routes.php). The controller can create users and insert database records. No authentication check. Visiting/install/initin a browser would recreate seed data, including writing admin users. - Impact: Any visitor can trigger
/install/user/adminwhich resets admin credentials toadmin/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/loginvia the catch-all route$config['admin/(.*)'] = 'admin/$1'. - Impact: Any visitor can visit
/admin/force/loginand 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->headerare 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 asmd5(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()withPASSWORD_BCRYPTorPASSWORD_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_failedtimestamp 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.regenerateis set to0(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. Usehttps://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 byIN_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 68–80) - Detail: If the PHP
filterextension is not installed,filter_var()is replaced with a stub that always returnstrue, 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_varis bypassed. - Fix: Require the
filterextension 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
Mysqldriver usesmysql_connect(),mysql_query(),mysql_close(), etc. These functions were removed in PHP 7.0. The application is configured to use themysqlidriver (application/config/database.php), but the oldMysql.phpdriver 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
mysqlidriver is always used. Deletesystem/libraries/drivers/Database/Mysql.phpor mark it clearly as unsupported.
[HIGH] Commented-out dead code throughout controllers
- Files:
application/controllers/admin/user.php(lines 8–10, 29–30, 46, 63),application/controllers/base_admin.php(lines 13, 31, 40–41),application/controllers/base_front.php(lines 12–17, 40–43) - Detail: Large blocks of commented-out functionality exist: disabled profiler, disabled cookie-based redirect, disabled homepage layout, disabled
__destructrendering. 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
gmapsmodule 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
gmapsmodule.
[MEDIUM] Adobe Flash integration
- Files:
flash/centrumcopy.swf,flash/expressInstall.swf,application/views/default_layout.php(lines 44–46, 94–102) - 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
swfobjectintegration 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.comis 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' => FALSEin production, or use theIN_PRODUCTIONflag 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.htaccesshas no asset caching rules. - Fix: Add browser caching rules in
.htaccessfor static file extensions.
[LOW] All front-end JavaScript loaded synchronously in <head>
- File:
application/views/default_layout.php(lines 18–30) - 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 usedefer/asyncattributes.
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 inCLAUDE.mdbutdb_schema.mddoes 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
.gitignoreexists (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), andapplication/logs/(log files) are all committed. - Fix: Create a
.gitignoreimmediately. 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->messageis never initialized as an object, so assigning to it on a modern PHP version throws an error. The code inUser_Controller::password()calls$this->message->password_success(line 108) which would also fail. - Fix: Initialize
$this->messageasnew stdClass()in theBase_Admin_Controllerconstructor, or replace with an array.
[MEDIUM] Duplicated forward() method in both base controllers
- Files:
application/controllers/base_admin.php(lines 68–86),application/controllers/base_front.php(lines 67–85) - 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 51–61),application/controllers/base_front.php(lines 51–60) - Detail: Same issue as
forward()— identical implementation in two classes. - Fix: Same resolution — extract to a shared parent.
[LOW] Copyright date is frozen at 2010
- 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, andnewsexist but no corresponding controllers, routes, or views for these features are present (the gallery and news routes exist inroutes.phpbut route to non-existent controllersfront/galleryandfront/news). - Impact: Visiting
/galeriaor/aktualnosciwill 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_testmodule is commented out inapplication/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.mdexplicitly 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 = falseis 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' => TRUEin 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-Policyheader in.htaccessor 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 109–118) uses the deprecatedga.jslibrary, notgtag.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