update
This commit is contained in:
274
.paul/codebase/concerns.md
Normal file
274
.paul/codebase/concerns.md
Normal file
@@ -0,0 +1,274 @@
|
||||
# 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 `<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 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 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`, 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 109–118) 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*
|
||||
Reference in New Issue
Block a user