@@ -152,6 +152,81 @@ Request → CI3 Hook (post_controller_constructor)
152152The write is a single append with ` LOCK_EX ` , so it does not block the request
153153and is safe for concurrent PHP-FPM workers.
154154
155+ ## Security
156+
157+ CI3 places ` index.php ` in the same directory as ` application/ ` , so by default
158+ everything under ` application/ ` — including ` application/logs/analysis.log ` ,
159+ which contains request headers and bodies — is reachable directly from the
160+ browser (` http://host/application/logs/analysis.log ` ). Apply at least one of
161+ the layers below; using all three is recommended.
162+
163+ ### 1. Keep ` application/ ` out of the web root (recommended)
164+
165+ Move the front controller so the public web root only contains ` index.php ` ,
166+ ` .htaccess ` and assets:
167+
168+ ```
169+ project/
170+ ├── application/ ← not web-accessible
171+ ├── system/
172+ └── public/ ← document root
173+ ├── index.php
174+ └── .htaccess
175+ ```
176+
177+ Then fix the paths in ` public/index.php ` (a copy of the original, with
178+ ` $system_path ` /` $application_folder ` updated to ` ../system ` and ` ../application ` )
179+ and set ` $config['base_url'] ` accordingly in ` application/config/config.php ` .
180+
181+ ### 2. Redirect the log directory outside the web root
182+
183+ Even with the default layout, point logs somewhere the browser cannot reach:
184+
185+ ``` ini
186+ REQUEST_LOG_DIR = " /var/log/myapp/request-analysis"
187+ ```
188+
189+ The hook falls back to ` application/logs ` only when ` REQUEST_LOG_DIR ` is empty.
190+
191+ ### 3. Deny access with the web server
192+
193+ ** Apache** — ship an ` .htaccess ` inside the log directory (and the
194+ ` application/ ` directory) with:
195+
196+ ``` apache
197+ <IfModule mod_authz_core.c>
198+ Require all denied
199+ </IfModule>
200+ <IfModule !mod_authz_core.c>
201+ Order deny,allow
202+ Deny from all
203+ </IfModule>
204+ ```
205+
206+ The sample app already includes ` sample/application/logs/.htaccess ` and
207+ ` sample/application/uploads/.htaccess ` . If ` AllowOverride ` is disabled, deny
208+ the paths in the vhost instead:
209+
210+ ``` apache
211+ <Directory "/path/to/app/application/logs">
212+ Require all denied
213+ </Directory>
214+ ```
215+
216+ ** Nginx** :
217+
218+ ``` nginx
219+ location ~ ^/(application|system)/ {
220+ deny all;
221+ }
222+ location ^~ /application/logs/ {
223+ deny all;
224+ }
225+ ```
226+
227+ ** Laravel-style check** — as a last line of defense, ` application/logs/.htaccess `
228+ also rejects ` *.log ` / ` *.gz ` matches even if directory-level rules are ignored.
229+
155230## Notes
156231
157232- The hook runs on every request once enabled. To log only specific
0 commit comments