# 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 68–80) - **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 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 `__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 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 `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 `
` - **File:** `application/views/default_layout.php` (lines 18–30) - **Detail:** 7+ JS files are loaded with blocking `